mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-04-22 00:33:59 +00:00
Implement fortune enchantment (#5757)
This commit is contained in:
parent
8c8794ec71
commit
fb6a7d279f
@ -23,9 +23,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use function mt_rand;
|
||||
|
||||
class Beetroot extends Crops{
|
||||
|
||||
@ -33,7 +33,7 @@ class Beetroot extends Crops{
|
||||
if($this->age >= self::MAX_AGE){
|
||||
return [
|
||||
VanillaItems::BEETROOT(),
|
||||
VanillaItems::BEETROOT_SEEDS()->setCount(mt_rand(0, 3))
|
||||
VanillaItems::BEETROOT_SEEDS()->setCount(FortuneDropHelper::binomial($item, 0))
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -23,15 +23,15 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use function mt_rand;
|
||||
|
||||
class Carrot extends Crops{
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [
|
||||
VanillaItems::CARROT()->setCount($this->age >= self::MAX_AGE ? mt_rand(1, 4) : 1)
|
||||
VanillaItems::CARROT()->setCount($this->age >= self::MAX_AGE ? FortuneDropHelper::binomial($item, 1) : 1)
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use function mt_rand;
|
||||
@ -31,7 +32,7 @@ class CoalOre extends Opaque{
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [
|
||||
VanillaItems::COAL()
|
||||
VanillaItems::COAL()->setCount(FortuneDropHelper::weighted($item, min: 1, maxBase: 1))
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -23,13 +23,16 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
|
||||
final class CopperOre extends Opaque{
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [VanillaItems::RAW_COPPER()];
|
||||
return [
|
||||
VanillaItems::RAW_COPPER()->setCount(FortuneDropHelper::weighted($item, min: 2, maxBase: 5)),
|
||||
];
|
||||
}
|
||||
|
||||
public function isAffectedBySilkTouch() : bool{ return true; }
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use function mt_rand;
|
||||
@ -31,7 +32,7 @@ class DiamondOre extends Opaque{
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [
|
||||
VanillaItems::DIAMOND()
|
||||
VanillaItems::DIAMOND()->setCount(FortuneDropHelper::weighted($item, min: 1, maxBase: 1))
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -23,9 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use function mt_rand;
|
||||
|
||||
class DoubleTallGrass extends DoublePlant{
|
||||
|
||||
@ -34,8 +33,8 @@ class DoubleTallGrass extends DoublePlant{
|
||||
}
|
||||
|
||||
public function getDropsForIncompatibleTool(Item $item) : array{
|
||||
if($this->top && mt_rand(0, 7) === 0){
|
||||
return [VanillaItems::WHEAT_SEEDS()];
|
||||
if($this->top){
|
||||
return FortuneDropHelper::grass($item);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use function mt_rand;
|
||||
@ -31,7 +32,7 @@ class EmeraldOre extends Opaque{
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [
|
||||
VanillaItems::EMERALD()
|
||||
VanillaItems::EMERALD()->setCount(FortuneDropHelper::weighted($item, min: 1, maxBase: 1))
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use function mt_rand;
|
||||
@ -30,7 +31,7 @@ use function mt_rand;
|
||||
final class GildedBlackstone extends Opaque{
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
if(mt_rand(1, 10) === 1){
|
||||
if(FortuneDropHelper::bonusChanceDivisor($item, 10, 3)){
|
||||
return [VanillaItems::GOLD_NUGGET()->setCount(mt_rand(2, 5))];
|
||||
}
|
||||
|
||||
|
@ -23,9 +23,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use function mt_rand;
|
||||
use function min;
|
||||
|
||||
class Glowstone extends Transparent{
|
||||
|
||||
@ -35,7 +36,7 @@ class Glowstone extends Transparent{
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [
|
||||
VanillaItems::GLOWSTONE_DUST()->setCount(mt_rand(2, 4))
|
||||
VanillaItems::GLOWSTONE_DUST()->setCount(min(4, FortuneDropHelper::discrete($item, 2, 4)))
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -25,15 +25,15 @@ namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\Fallable;
|
||||
use pocketmine\block\utils\FallableTrait;
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use function mt_rand;
|
||||
|
||||
class Gravel extends Opaque implements Fallable{
|
||||
use FallableTrait;
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
if(mt_rand(1, 10) === 1){
|
||||
if(FortuneDropHelper::bonusChanceDivisor($item, 10, 3)){
|
||||
return [
|
||||
VanillaItems::FLINT()
|
||||
];
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use function mt_rand;
|
||||
@ -31,7 +32,7 @@ class LapisOre extends Opaque{
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [
|
||||
VanillaItems::LAPIS_LAZULI()->setCount(mt_rand(4, 8))
|
||||
VanillaItems::LAPIS_LAZULI()->setCount(FortuneDropHelper::weighted($item, min: 4, maxBase: 9))
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\block\utils\LeavesType;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
@ -138,7 +139,8 @@ class Leaves extends Transparent{
|
||||
}
|
||||
|
||||
$drops = [];
|
||||
if(mt_rand(1, 20) === 1){ //Saplings
|
||||
if(FortuneDropHelper::bonusChanceDivisor($item, 20, 4)){ //Saplings
|
||||
// TODO: according to the wiki, the jungle saplings have a different drop rate
|
||||
$sapling = (match($this->leavesType){
|
||||
LeavesType::ACACIA() => VanillaBlocks::ACACIA_SAPLING(),
|
||||
LeavesType::BIRCH() => VanillaBlocks::BIRCH_SAPLING(),
|
||||
@ -155,10 +157,13 @@ class Leaves extends Transparent{
|
||||
$drops[] = $sapling;
|
||||
}
|
||||
}
|
||||
if(($this->leavesType->equals(LeavesType::OAK()) || $this->leavesType->equals(LeavesType::DARK_OAK())) && mt_rand(1, 200) === 1){ //Apples
|
||||
if(
|
||||
($this->leavesType->equals(LeavesType::OAK()) || $this->leavesType->equals(LeavesType::DARK_OAK())) &&
|
||||
FortuneDropHelper::bonusChanceDivisor($item, 200, 20)
|
||||
){ //Apples
|
||||
$drops[] = VanillaItems::APPLE();
|
||||
}
|
||||
if(mt_rand(1, 50) === 1){
|
||||
if(FortuneDropHelper::bonusChanceDivisor($item, 50, 5)){
|
||||
$drops[] = VanillaItems::STICK()->setCount(mt_rand(1, 2));
|
||||
}
|
||||
|
||||
|
@ -23,15 +23,16 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use function mt_rand;
|
||||
use function min;
|
||||
|
||||
class Melon extends Opaque{
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [
|
||||
VanillaItems::MELON()->setCount(mt_rand(3, 7))
|
||||
VanillaItems::MELON()->setCount(min(9, FortuneDropHelper::discrete($item, 3, 7)))
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -23,14 +23,14 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use function mt_rand;
|
||||
|
||||
final class NetherGoldOre extends Opaque{
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [VanillaItems::GOLD_NUGGET()->setCount(mt_rand(2, 6))];
|
||||
return [VanillaItems::GOLD_NUGGET()->setCount(FortuneDropHelper::weighted($item, min: 2, maxBase: 6))];
|
||||
}
|
||||
|
||||
public function isAffectedBySilkTouch() : bool{ return true; }
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use function mt_rand;
|
||||
@ -31,7 +32,7 @@ class NetherQuartzOre extends Opaque{
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [
|
||||
VanillaItems::NETHER_QUARTZ()
|
||||
VanillaItems::NETHER_QUARTZ()->setCount(FortuneDropHelper::weighted($item, min: 1, maxBase: 1))
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\entity\Entity;
|
||||
@ -179,7 +180,7 @@ class NetherVines extends Flowable{
|
||||
}
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
if(($item->getBlockToolType() & BlockToolType::SHEARS) !== 0 || mt_rand(1, 3) === 1){
|
||||
if(($item->getBlockToolType() & BlockToolType::SHEARS) !== 0 || FortuneDropHelper::bonusChanceFixed($item, 1 / 3, 2 / 9)){
|
||||
return [$this->asItem()];
|
||||
}
|
||||
return [];
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\event\block\BlockGrowEvent;
|
||||
use pocketmine\item\Item;
|
||||
@ -85,7 +86,7 @@ class NetherWartPlant extends Flowable{
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [
|
||||
$this->asItem()->setCount($this->age === self::MAX_AGE ? mt_rand(2, 4) : 1)
|
||||
$this->asItem()->setCount($this->age === self::MAX_AGE ? FortuneDropHelper::discrete($item, 2, 4) : 1)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use function mt_rand;
|
||||
@ -31,7 +32,8 @@ class Potato extends Crops{
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
$result = [
|
||||
VanillaItems::POTATO()->setCount($this->age >= self::MAX_AGE ? mt_rand(1, 5) : 1)
|
||||
//min/max would be 2-5 in Java
|
||||
VanillaItems::POTATO()->setCount($this->age >= self::MAX_AGE ? FortuneDropHelper::binomial($item, 1) : 1)
|
||||
];
|
||||
if($this->age >= self::MAX_AGE && mt_rand(0, 49) === 0){
|
||||
$result[] = VanillaItems::POISONOUS_POTATO();
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
@ -81,7 +82,7 @@ class RedstoneOre extends Opaque{
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [
|
||||
VanillaItems::REDSTONE_DUST()->setCount(mt_rand(4, 5))
|
||||
VanillaItems::REDSTONE_DUST()->setCount(FortuneDropHelper::discrete($item, 4, 5))
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -23,8 +23,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use function min;
|
||||
|
||||
class SeaLantern extends Transparent{
|
||||
|
||||
@ -34,7 +36,7 @@ class SeaLantern extends Transparent{
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
return [
|
||||
VanillaItems::PRISMARINE_CRYSTALS()->setCount(3)
|
||||
VanillaItems::PRISMARINE_CRYSTALS()->setCount(min(5, FortuneDropHelper::discrete($item, 2, 3)))
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\Living;
|
||||
@ -108,13 +109,14 @@ class SweetBerryBush extends Flowable{
|
||||
}
|
||||
|
||||
public function getDropsForCompatibleTool(Item $item) : array{
|
||||
if(($dropAmount = $this->getBerryDropAmount()) > 0){
|
||||
return [
|
||||
$this->asItem()->setCount($dropAmount)
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
$count = match($this->age){
|
||||
self::STAGE_MATURE => FortuneDropHelper::discrete($item, 2, 3),
|
||||
self::STAGE_BUSH_SOME_BERRIES => FortuneDropHelper::discrete($item, 1, 2),
|
||||
default => 0
|
||||
};
|
||||
return [
|
||||
$this->asItem()->setCount($count)
|
||||
];
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
|
@ -23,13 +23,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use function mt_rand;
|
||||
|
||||
class TallGrass extends Flowable{
|
||||
|
||||
@ -56,13 +55,7 @@ class TallGrass extends Flowable{
|
||||
}
|
||||
|
||||
public function getDropsForIncompatibleTool(Item $item) : array{
|
||||
if(mt_rand(0, 15) === 0){
|
||||
return [
|
||||
VanillaItems::WHEAT_SEEDS()
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
return FortuneDropHelper::grass($item);
|
||||
}
|
||||
|
||||
public function getFlameEncouragement() : int{
|
||||
|
@ -23,9 +23,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block;
|
||||
|
||||
use pocketmine\block\utils\FortuneDropHelper;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use function mt_rand;
|
||||
|
||||
class Wheat extends Crops{
|
||||
|
||||
@ -33,7 +33,7 @@ class Wheat extends Crops{
|
||||
if($this->age >= self::MAX_AGE){
|
||||
return [
|
||||
VanillaItems::WHEAT(),
|
||||
VanillaItems::WHEAT_SEEDS()->setCount(mt_rand(0, 3))
|
||||
VanillaItems::WHEAT_SEEDS()->setCount(FortuneDropHelper::binomial($item, 0))
|
||||
];
|
||||
}else{
|
||||
return [
|
||||
|
150
src/block/utils/FortuneDropHelper.php
Normal file
150
src/block/utils/FortuneDropHelper.php
Normal file
@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
*
|
||||
* ____ _ _ __ __ _ __ __ ____
|
||||
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
|
||||
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
|
||||
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
|
||||
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* @author PocketMine Team
|
||||
* @link http://www.pocketmine.net/
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\block\utils;
|
||||
|
||||
use pocketmine\item\enchantment\VanillaEnchantments;
|
||||
use pocketmine\item\Item;
|
||||
use pocketmine\item\VanillaItems;
|
||||
use function max;
|
||||
use function min;
|
||||
use function mt_getrandmax;
|
||||
use function mt_rand;
|
||||
|
||||
final class FortuneDropHelper{
|
||||
/**
|
||||
* If a random number between 0-1 is greater than 2/(level+2), this multiplies the max drop amount by level+1, and
|
||||
* picks a random amount between the minimum and multiplied maximum. Each level of fortune increases the chance of
|
||||
* fortune activation, and also increases the maximum drop limit when activated.
|
||||
*
|
||||
* Otherwise, returns a random amount of the item between the minimum and original maximum.
|
||||
*
|
||||
* @param Item $usedItem The item used to break the block
|
||||
* @param int $min Minimum amount
|
||||
* @param int $maxBase Maximum amount, as if fortune level was 0
|
||||
*
|
||||
* @return int the number of items to drop
|
||||
*/
|
||||
public static function weighted(Item $usedItem, int $min, int $maxBase) : int{
|
||||
if($maxBase < $min){
|
||||
throw new \InvalidArgumentException("Maximum drop amount must be greater than or equal to minimum drop amount");
|
||||
}
|
||||
|
||||
$fortuneLevel = $usedItem->getEnchantmentLevel(VanillaEnchantments::FORTUNE());
|
||||
|
||||
return mt_rand($min,
|
||||
$fortuneLevel > 0 && mt_rand() / mt_getrandmax() > 2 / ($fortuneLevel + 2) ?
|
||||
$maxBase * ($fortuneLevel + 1) :
|
||||
$maxBase
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases the drop amount according to a binomial distribution. The function will roll maxBase+level times, and add 1
|
||||
* if a random number between 0-1 is less than the given probability. Each level of fortune adds one extra roll.
|
||||
*
|
||||
* As many as maxBase+level items can be dropped. This applies even if the fortune level is 0.
|
||||
*
|
||||
* @param float $chance The chance of adding 1 to the amount for each roll, must be in the range 0-1
|
||||
* @param int $min Minimum amount
|
||||
* @param int $minRolls Number of rolls if fortune level is 0, added to fortune level to calculate total rolls
|
||||
*
|
||||
* @return int the number of items to drop
|
||||
*/
|
||||
public static function binomial(Item $usedItem, int $min, int $minRolls = 3, float $chance = 4 / 7) : int{
|
||||
$fortuneLevel = $usedItem->getEnchantmentLevel(VanillaEnchantments::FORTUNE());
|
||||
|
||||
$count = $min;
|
||||
$rolls = $minRolls + $fortuneLevel;
|
||||
for($i = 0; $i < $rolls; ++$i){
|
||||
if(mt_rand() / mt_getrandmax() < $chance){
|
||||
++$count;
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grass have a fixed chance to drop wheat seed.
|
||||
* Fortune level increases the maximum number of seeds that can be dropped.
|
||||
* A discrete uniform distribution is used to determine the number of seeds dropped.
|
||||
*
|
||||
* TODO: I'm not sure this really belongs here, but it's preferable not to duplicate this code between grass and
|
||||
* tall grass.
|
||||
*
|
||||
* @return Item[]
|
||||
*/
|
||||
public static function grass(Item $usedItem) : array{
|
||||
if(FortuneDropHelper::bonusChanceDivisor($usedItem, 8, 2)){
|
||||
return [
|
||||
VanillaItems::WHEAT_SEEDS()
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the fortune level to the base max and picks a random number between the minimim and adjusted maximum.
|
||||
* Each amount in the range has an equal chance of being picked.
|
||||
*
|
||||
* @param int $maxBase Maximum base amount, as if the fortune level was 0
|
||||
*
|
||||
* @return int the number of items to drop
|
||||
*/
|
||||
public static function discrete(Item $usedItem, int $min, int $maxBase) : int{
|
||||
if($maxBase < $min){
|
||||
throw new \InvalidArgumentException("Minimum base drop amount must be less than or equal to maximum base drop amount");
|
||||
}
|
||||
|
||||
$max = $maxBase + $usedItem->getEnchantmentLevel(VanillaEnchantments::FORTUNE());
|
||||
return mt_rand($min, $max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates a chance of getting an extra bonus drop by reducing the chance divisor by a given amount per fortune
|
||||
* level.
|
||||
*
|
||||
* @param int $divisorBase The number to divide 1 by to get the chance, as if the fortune level was 0
|
||||
* @param int $divisorSubtractPerLevel The amount to subtract from the divisor for each level of fortune
|
||||
*
|
||||
* @return bool whether the bonus drop should be added
|
||||
*/
|
||||
public static function bonusChanceDivisor(Item $usedItem, int $divisorBase, int $divisorSubtractPerLevel) : bool{
|
||||
$fortuneLevel = $usedItem->getEnchantmentLevel(VanillaEnchantments::FORTUNE());
|
||||
return mt_rand(1, max(1, $divisorBase - ($fortuneLevel * $divisorSubtractPerLevel))) === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates a chance of getting an extra bonus drop by increasing the chance by a fixed amount per fortune level.
|
||||
*
|
||||
* @param float $chanceBase The base chance of getting a bonus drop, as if the fortune level was 0
|
||||
* @param float $addedChancePerLevel The amount to add to the chance for each level of fortune
|
||||
*/
|
||||
public static function bonusChanceFixed(Item $usedItem, float $chanceBase, float $addedChancePerLevel) : bool{
|
||||
$fortuneLevel = $usedItem->getEnchantmentLevel(VanillaEnchantments::FORTUNE());
|
||||
$chance = min(1, $chanceBase + ($fortuneLevel * $addedChancePerLevel));
|
||||
return mt_rand() / mt_getrandmax() < $chance;
|
||||
}
|
||||
}
|
@ -62,6 +62,7 @@ final class EnchantmentIdMap{
|
||||
$this->register(EnchantmentIds::FIRE_ASPECT, VanillaEnchantments::FIRE_ASPECT());
|
||||
|
||||
$this->register(EnchantmentIds::EFFICIENCY, VanillaEnchantments::EFFICIENCY());
|
||||
$this->register(EnchantmentIds::FORTUNE, VanillaEnchantments::FORTUNE());
|
||||
$this->register(EnchantmentIds::SILK_TOUCH, VanillaEnchantments::SILK_TOUCH());
|
||||
$this->register(EnchantmentIds::UNBREAKING, VanillaEnchantments::UNBREAKING());
|
||||
|
||||
|
@ -43,6 +43,7 @@ final class StringToEnchantmentParser extends StringToTParser{
|
||||
$result->register("fire_aspect", fn() => VanillaEnchantments::FIRE_ASPECT());
|
||||
$result->register("fire_protection", fn() => VanillaEnchantments::FIRE_PROTECTION());
|
||||
$result->register("flame", fn() => VanillaEnchantments::FLAME());
|
||||
$result->register("fortune", fn() => VanillaEnchantments::FORTUNE());
|
||||
$result->register("infinity", fn() => VanillaEnchantments::INFINITY());
|
||||
$result->register("knockback", fn() => VanillaEnchantments::KNOCKBACK());
|
||||
$result->register("mending", fn() => VanillaEnchantments::MENDING());
|
||||
|
@ -39,6 +39,7 @@ use pocketmine\utils\RegistryTrait;
|
||||
* @method static FireAspectEnchantment FIRE_ASPECT()
|
||||
* @method static ProtectionEnchantment FIRE_PROTECTION()
|
||||
* @method static Enchantment FLAME()
|
||||
* @method static Enchantment FORTUNE()
|
||||
* @method static Enchantment INFINITY()
|
||||
* @method static KnockbackEnchantment KNOCKBACK()
|
||||
* @method static Enchantment MENDING()
|
||||
@ -85,6 +86,7 @@ final class VanillaEnchantments{
|
||||
self::register("FIRE_ASPECT", new FireAspectEnchantment(KnownTranslationFactory::enchantment_fire(), Rarity::RARE, ItemFlags::SWORD, ItemFlags::NONE, 2));
|
||||
|
||||
self::register("EFFICIENCY", new Enchantment(KnownTranslationFactory::enchantment_digging(), Rarity::COMMON, ItemFlags::DIG, ItemFlags::SHEARS, 5));
|
||||
self::register("FORTUNE", new Enchantment(KnownTranslationFactory::enchantment_lootBonusDigger(), Rarity::RARE, ItemFlags::DIG, ItemFlags::NONE, 3));
|
||||
self::register("SILK_TOUCH", new Enchantment(KnownTranslationFactory::enchantment_untouching(), Rarity::MYTHIC, ItemFlags::DIG, ItemFlags::SHEARS, 1));
|
||||
self::register("UNBREAKING", new Enchantment(KnownTranslationFactory::enchantment_durability(), Rarity::UNCOMMON, ItemFlags::DIG | ItemFlags::ARMOR | ItemFlags::FISHING_ROD | ItemFlags::BOW, ItemFlags::TOOL | ItemFlags::CARROT_STICK | ItemFlags::ELYTRA, 3));
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user