Implemented hunger-related regen and damage

This commit is contained in:
PEMapModder 2016-02-11 01:53:51 +08:00
parent 329a525ea1
commit 52e8781d36
5 changed files with 123 additions and 11 deletions

View File

@ -2260,6 +2260,8 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
$this->inventory->setItemInHand($item);
$this->inventory->sendHeldItem($this->hasSpawned);
}
$this->exhaust(0.025);
}
break;
}
@ -2294,7 +2296,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
if(
$target instanceof Player and
$this->server->getConfigBoolean("pvp", true) === false
){
$cancelled = true;
}
@ -2392,13 +2393,17 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
break;
}
if($item->isTool() and $this->isSurvival()){
if($this->isSurvival()){
if($item->isTool()){
if($item->useOn($target) and $item->getDamage() >= $item->getMaxDurability()){
$this->inventory->setItemInHand(Item::get(Item::AIR, 0, 1));
}else{
$this->inventory->setItemInHand($item);
}
}
$this->exhaust(0.3);
}
}
break;
@ -3259,6 +3264,10 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
$pk->eid = 0;
$pk->event = EntityEventPacket::HURT_ANIMATION;
$this->dataPacket($pk);
if($this->isSurvival()){
$this->exhaust(0.3);
}
}
}

View File

@ -201,6 +201,14 @@ class Effect{
return ($this->duration % $interval) === 0;
}
return true;
case Effect::HUNGER:
if($this->amplifier < 0){ // prevents hacking with amplifier -1
return false;
}
if(($interval = 20) > 0){
return ($this->duration % $interval) === 0;
}
return true;
}
return false;
}
@ -225,6 +233,11 @@ class Effect{
$entity->heal($ev->getAmount(), $ev);
}
break;
case Effect::HUNGER:
if($entity instanceof Human){
$entity->exhaust(0.5 * $this->amplifier);
}
}
}

View File

@ -21,6 +21,8 @@
namespace pocketmine\entity;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\EntityRegainHealthEvent;
use pocketmine\inventory\InventoryHolder;
use pocketmine\inventory\PlayerInventory;
use pocketmine\item\Item as ItemItem;
@ -58,6 +60,8 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
protected $skinName;
protected $skin;
protected $foodTickTimer = 0;
public function getSkinData(){
return $this->skin;
}
@ -93,18 +97,47 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
return (float) $this->attributeMap->getAttribute(Attribute::HUNGER)->getValue();
}
public function setFood(float $food){
$this->attributeMap->getAttribute(Attribute::HUNGER)->setValue($food);
/**
* WARNING: This method does not check if full and may throw an exception if out of bounds.
* Use {@link Human::addFood()} for this purpose
*
* @param float $new
*
* @throws \InvalidArgumentException
*/
public function setFood(float $new){
$attr = $this->attributeMap->getAttribute(Attribute::HUNGER);
$old = $attr->getValue();
$attr->setValue($new);
// ranges: 18-20 (regen), 7-17 (none), 1-6 (no sprint), 0 (health depletion)
foreach([17, 6, 0] as $bound){
if(($old > $bound) !== ($new > $bound)){
$reset = true;
}
}
if(isset($reset)){
$this->foodTickTimer = 0;
}
}
public function addFood(float $amount){
$this->attributeMap->getAttribute(Attribute::HUNGER)->setValue($amount, true);
$attr = $this->attributeMap->getAttribute(Attribute::HUNGER);
$amount = max(min($amount, $attr->getMaxValue()), $attr->getMinValue());
$this->setFood($amount);
}
public function getSaturation() : float{
return $this->attributeMap->getAttribute(Attribute::HUNGER)->getValue();
}
/**
* WARNING: This method does not check if saturated and may throw an exception if out of bounds.
* Use {@link Human::addSaturation()} for this purpose
*
* @param float $saturation
*
* @throws \InvalidArgumentException
*/
public function setSaturation(float $saturation){
$this->attributeMap->getAttribute(Attribute::HUNGER)->setValue($saturation);
}
@ -117,15 +150,32 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
return $this->attributeMap->getAttribute(Attribute::EXHAUSTION)->getValue();
}
/**
* WARNING: This method does not check if exhausted and does not consume saturation/food.
* Use {@link Human::exhaust()} for this purpose.
*
* @param float $exhaustion
*/
public function setExhaustion(float $exhaustion){
$this->attributeMap->getAttribute(Attribute::EXHAUSTION)->setValue($exhaustion);
}
/**
* Increases a human's exhaustion level.
* TODO walk per meter: 0.01
* TODO sneak per meter: 0.005
* TODO swim per meter: 0.015
* TODO sprint per meter: 0.1
* TODO jump: 0.2
* TODO regen per halfheart | food >= 18: 4.0
*
* @param float $amount
*/
public function exhaust(float $amount){
$exhaustion = $this->getExhaustion();
$exhaustion += $amount;
if($exhaustion >= 4.0){
while($exhaustion >= 4.0){
$exhaustion -= 4.0;
$this->setExhaustion($exhaustion);
@ -181,14 +231,52 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
}
}
parent::initEntity();
$this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::SATURATION));
$this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::EXHAUSTION));
$this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::HUNGER));
$this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::ATTACK_DAMAGE));
$this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::EXPERIENCE_LEVEL));
$this->attributeMap->addAttribute(Attribute::getAttribute(Attribute::EXPERIENCE));
}
parent::initEntity();
public function entityBaseTick($tickDiff = 1){
$hasUpdate = parent::entityBaseTick($tickDiff);
$food = $this->getFood();
$health = $this->getHealth();
if($food >= 18){
$this->foodTickTimer++;
if($this->foodTickTimer >= 80){
$this->heal(1, new EntityRegainHealthEvent($this, 1, EntityRegainHealthEvent::CAUSE_SATURATION));
$this->exhaust(3.0);
$this->foodTickTimer = 0;
}
}elseif($food === 0){
$this->foodTickTimer++;
if($this->foodTickTimer >= 80){
$diff = $this->server->getDifficulty();
$can = false;
if($diff === 1){
$can = $health > 10;
}elseif($diff === 2){
$can = $health > 1;
}elseif($diff === 3){
$can = true;
}
if($can){
$this->attack(1, new EntityDamageEvent($this, EntityDamageEvent::CAUSE_STARVATION, 1));
}
}
}
if($food <= 6){
if($this->isSprinting()){
$this->setSprinting(false);
}
}
return $hasUpdate;
}
public function getName(){

View File

@ -49,6 +49,7 @@ class EntityDamageEvent extends EntityEvent implements Cancellable{
const CAUSE_SUICIDE = 12;
const CAUSE_MAGIC = 13;
const CAUSE_CUSTOM = 14;
const CAUSE_STARVATION = 15;
private $cause;

View File

@ -31,6 +31,7 @@ class EntityRegainHealthEvent extends EntityEvent implements Cancellable{
const CAUSE_EATING = 1;
const CAUSE_MAGIC = 2;
const CAUSE_CUSTOM = 3;
const CAUSE_SATURATION = 4;
private $amount;
private $reason;