PocketMine-MP  1.4 - API 1.10.0
 All Classes Namespaces Functions Variables Pages
Living.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 
31 use pocketmine\item\Item as ItemItem;
38 
39 abstract class Living extends Entity implements Damageable{
40 
41  protected $gravity = 0.08;
42  protected $drag = 0.02;
43 
44  protected $attackTime = 0;
45 
46  protected function initEntity(){
47  if(isset($this->namedtag->HealF)){
48  $this->namedtag->Health = new Short("Health", (int) $this->namedtag["HealF"]);
49  unset($this->namedtag->HealF);
50  }
51 
52  if(!isset($this->namedtag->Health) or !($this->namedtag->Health instanceof Short)){
53  $this->namedtag->Health = new Short("Health", $this->getMaxHealth());
54  }
55 
56  $this->setHealth($this->namedtag["Health"]);
57  }
58 
59  public function saveNBT(){
60  parent::saveNBT();
61  $this->namedtag->Health = new Short("Health", $this->getHealth());
62  }
63 
64  public abstract function getName();
65 
66  public function hasLineOfSight(Entity $entity){
67  //TODO: head height
68  return true;
69  //return $this->getLevel()->rayTraceBlocks(Vector3::createVector($this->x, $this->y + $this->height, $this->z), Vector3::createVector($entity->x, $entity->y + $entity->height, $entity->z)) === null;
70  }
71 
72  public function attack($damage, $source = EntityDamageEvent::CAUSE_MAGIC){
73  if($this->attackTime > 0 or $this->noDamageTicks > 0){
74  $lastCause = $this->getLastDamageCause();
75  if($lastCause instanceof EntityDamageEvent and $lastCause->getDamage() >= $damage){
76  if($source instanceof EntityDamageEvent){
77  $source->setCancelled();
78  $this->server->getPluginManager()->callEvent($source);
79  $damage = $source->getFinalDamage();
80  if($source->isCancelled()){
81  return;
82  }
83  }else{
84  return;
85  }
86  }else{
87  return;
88  }
89  }elseif($source instanceof EntityDamageEvent){
90  $this->server->getPluginManager()->callEvent($source);
91  $damage = $source->getFinalDamage();
92  if($source->isCancelled()){
93  return;
94  }
95  }
96 
97  $this->setLastDamageCause($source);
98 
99  if($source instanceof EntityDamageByEntityEvent){
100  $e = $source->getDamager();
101  $deltaX = $this->x - $e->x;
102  $deltaZ = $this->z - $e->z;
103  $yaw = atan2($deltaX, $deltaZ);
104  $this->knockBack($e, $damage, sin($yaw), cos($yaw), $source->getKnockBack());
105  }
106 
107  $this->setHealth($this->getHealth() - $damage);
108 
109  $pk = new EntityEventPacket();
110  $pk->eid = $this->getId();
111  $pk->event = $this->getHealth() <= 0 ? 3 : 2; //Ouch!
112  Server::broadcastPacket($this->hasSpawned, $pk);
113 
114  $this->attackTime = 10; //0.5 seconds cooldown
115  }
116 
117  public function knockBack(Entity $attacker, $damage, $x, $z, $base = 0.4){
118  $f = sqrt($x ** 2 + $z ** 2);
119 
120  $motion = new Vector3($this->motionX, $this->motionY, $this->motionZ);
121 
122  $motion->x /= 2;
123  $motion->y /= 2;
124  $motion->z /= 2;
125  $motion->x += ($x / $f) * $base;
126  $motion->y += $base;
127  $motion->z += ($z / $f) * $base;
128 
129  if($motion->y > $base){
130  $motion->y = $base;
131  }
132 
133  $this->setMotion($motion);
134  }
135 
136  public function heal($amount, $source = EntityRegainHealthEvent::CAUSE_MAGIC){
137  $this->setHealth($this->getHealth() + $amount);
138  }
139 
140  public function kill(){
141  if($this->dead){
142  return;
143  }
144  parent::kill();
145  $this->server->getPluginManager()->callEvent($ev = new EntityDeathEvent($this, $this->getDrops()));
146  foreach($ev->getDrops() as $item){
147  $this->getLevel()->dropItem($this, $item);
148  }
149  }
150 
151  public function entityBaseTick($tickDiff = 1){
152  Timings::$timerEntityBaseTick->startTiming();
153 
154  if($this->dead === true){
155  ++$this->deadTicks;
156  if($this->deadTicks >= 10){
157  $this->despawnFromAll();
158  if(!($this instanceof Player)){
159  $this->close();
160  }
161  }
162 
163  Timings::$timerEntityBaseTick->stopTiming();
164  return $this->deadTicks < 10;
165  }
166 
167  parent::entityBaseTick($tickDiff);
168 
169  if($this->dead !== true and $this->isInsideOfSolid()){
170  $ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_SUFFOCATION, 1);
171  $this->attack($ev->getFinalDamage(), $ev);
172  }
173 
174  if($this->dead !== true and $this->isInsideOfWater()){
175  $this->airTicks -= $tickDiff;
176  if($this->airTicks <= -20){
177  $this->airTicks = 0;
178 
179  $ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_DROWNING, 2);
180  $this->attack($ev->getFinalDamage(), $ev);
181  }
182  }else{
183  $this->airTicks = 300;
184  }
185 
186  if($this->attackTime > 0){
187  $this->attackTime -= $tickDiff;
188  }
189 
190  Timings::$timerEntityBaseTick->stopTiming();
191  }
192 
196  public function getDrops(){
197  return [];
198  }
199 
207  public function getLineOfSight($maxDistance, $maxLength = 0, array $transparent = []){
208  if($maxDistance > 120){
209  $maxDistance = 120;
210  }
211 
212  if(count($transparent) === 0){
213  $transparent = null;
214  }
215 
216  $blocks = [];
217  $nextIndex = 0;
218 
219  $itr = new BlockIterator($this->level, $this->getPosition(), $this->getDirectionVector(), $this->getEyeHeight(), $maxDistance);
220 
221  while($itr->valid()){
222  $itr->next();
223  $block = $itr->current();
224  $blocks[$nextIndex++] = $block;
225 
226  if($maxLength !== 0 and count($blocks) > $maxLength){
227  array_shift($blocks);
228  --$nextIndex;
229  }
230 
231  $id = $block->getId();
232 
233  if($transparent === null){
234  if($id !== 0){
235  break;
236  }
237  }else{
238  if(!isset($transparent[$id])){
239  break;
240  }
241  }
242  }
243 
244  return $blocks;
245  }
246 
253  public function getTargetBlock($maxDistance, array $transparent = []){
254  try{
255  $block = $this->getLineOfSight($maxDistance, 1, $transparent)[0];
256  if($block instanceof Block){
257  return $block;
258  }
259  }catch (\ArrayOutOfBoundsException $e){
260 
261  }
262 
263  return null;
264  }
265 }
getLineOfSight($maxDistance, $maxLength=0, array $transparent=[])
Definition: Living.php:207
getTargetBlock($maxDistance, array $transparent=[])
Definition: Living.php:253
static broadcastPacket(array $players, DataPacket $packet)
Definition: Server.php:1725