PocketMine-MP  1.4 - API 1.10.0
 All Classes Namespaces Functions Variables Pages
Projectile.php
1 <?php
2 
3 /*
4  *
5  * ____ _ _ __ __ _ __ __ ____
6  * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7  * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8  * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9  * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * @author PocketMine Team
17  * @link http://www.pocketmine.net/
18  *
19  *
20 */
21 
22 namespace pocketmine\entity;
23 
24 
34 
35 abstract class Projectile extends Entity{
37  public $shootingEntity = null;
38  protected $damage = 0;
39 
40  private $hadCollision = false;
41 
42  protected function initEntity(){
43  $this->setMaxHealth(1);
44  $this->setHealth(1);
45  if(isset($this->namedtag->Age)){
46  $this->age = $this->namedtag["Age"];
47  }
48 
49  }
50 
51  public function canCollideWith(Entity $entity){
52  return $entity instanceof Living and !$this->onGround;
53  }
54 
55  public function getData(){
56  $flags = 0;
57  $flags |= $this->fireTicks > 0 ? 1 : 0;
58 
59  return [
60  0 => ["type" => 0, "value" => $flags],
61  1 => ["type" => 1, "value" => $this->airTicks],
62  16 => ["type" => 0, "value" => 0] //Is critical
63  ];
64  }
65 
66  public function saveNBT(){
67  parent::saveNBT();
68  $this->namedtag->Age = new Short("Age", $this->age);
69  }
70 
71  public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){
72 
73  }
74 
75  public function heal($amount, $source = EntityRegainHealthEvent::CAUSE_MAGIC){
76 
77  }
78 
79  public function onUpdate($currentTick){
80  if($this->closed){
81  return false;
82  }
83 
84 
85  $tickDiff = max(1, $currentTick - $this->lastUpdate);
86  $this->lastUpdate = $currentTick;
87 
88  $hasUpdate = $this->entityBaseTick($tickDiff);
89 
90  if(!$this->dead){
91 
92  $movingObjectPosition = null;
93 
94  if(!$this->isCollided){
95  $this->motionY -= $this->gravity;
96  }
97 
98  $this->keepMovement = $this->checkObstruction($this->x, ($this->boundingBox->minY + $this->boundingBox->maxY) / 2, $this->z);
99 
100  $moveVector = new Vector3($this->x + $this->motionX, $this->y + $this->motionY, $this->z + $this->motionZ);
101 
102  $list = $this->getLevel()->getCollidingEntities($this->boundingBox->addCoord($this->motionX, $this->motionY, $this->motionZ)->expand(1, 1, 1), $this);
103 
104  $nearDistance = PHP_INT_MAX;
105  $nearEntity = null;
106 
107  foreach($list as $entity){
108  if(
109  ($entity === $this->shootingEntity and $this->ticksLived < 5)
110  ){
111  continue;
112  }
113 
114  $axisalignedbb = $entity->boundingBox->grow(0.3, 0.3, 0.3);
115  $ob = $axisalignedbb->calculateIntercept($this, $moveVector);
116 
117  if($ob === null){
118  continue;
119  }
120 
121  $distance = $this->distanceSquared($ob->hitVector);
122 
123  if($distance < $nearDistance){
124  $nearDistance = $distance;
125  $nearEntity = $entity;
126  }
127  }
128 
129  if($nearEntity !== null){
130  $movingObjectPosition = MovingObjectPosition::fromEntity($nearEntity);
131  }
132 
133  if($movingObjectPosition !== null){
134  if($movingObjectPosition->entityHit !== null){
135 
136  $this->server->getPluginManager()->callEvent(new ProjectileHitEvent($this));
137 
138  $motion = sqrt($this->motionX ** 2 + $this->motionY ** 2 + $this->motionZ ** 2);
139  $damage = ceil($motion * $this->damage);
140 
141  if($this->shootingEntity === null){
142  $ev = new EntityDamageByEntityEvent($this, $movingObjectPosition->entityHit, EntityDamageEvent::CAUSE_PROJECTILE, $damage);
143  }else{
144  $ev = new EntityDamageByChildEntityEvent($this->shootingEntity, $this, $movingObjectPosition->entityHit, EntityDamageEvent::CAUSE_PROJECTILE, $damage);
145  }
146 
147  $movingObjectPosition->entityHit->attack($ev->getFinalDamage(), $ev);
148 
149 
150  if($this->fireTicks > 0){
151  $ev = new EntityCombustByEntityEvent($this, $movingObjectPosition->entityHit, 5);
152  $this->server->getPluginManager()->callEvent($ev);
153  if(!$ev->isCancelled()){
154  $movingObjectPosition->entityHit->setOnFire($ev->getDuration());
155  }
156  }
157 
158  $this->kill();
159  return true;
160  }
161  }
162 
163  $this->move($this->motionX, $this->motionY, $this->motionZ);
164 
165  if($this->isCollided and !$this->hadCollision){
166  $this->hadCollision = true;
167 
168  $this->motionX = 0;
169  $this->motionY = 0;
170  $this->motionZ = 0;
171 
172  $this->server->getPluginManager()->callEvent(new ProjectileHitEvent($this));
173  }elseif(!$this->isCollided and !$this->hadCollision){
174  $this->hadCollision = false;
175  }
176 
177  if(!$this->onGround or $this->motionX != 0 or $this->motionY != 0 or $this->motionZ != 0){
178  $f = sqrt(($this->motionX ** 2) + ($this->motionZ ** 2));
179  $this->yaw = (atan2($this->motionX, $this->motionZ) * 180 / M_PI);
180  $this->pitch = (atan2($this->motionY, $f) * 180 / M_PI);
181  $hasUpdate = true;
182  }
183 
184  $this->updateMovement();
185 
186  }
187 
188  return $hasUpdate;
189  }
190 
191 }