github.com/df-mc/dragonfly@v0.9.13/server/item/bow.go (about)

     1  package item
     2  
     3  import (
     4  	"github.com/df-mc/dragonfly/server/block/cube"
     5  	"github.com/df-mc/dragonfly/server/item/potion"
     6  	"github.com/df-mc/dragonfly/server/world/sound"
     7  	"math"
     8  	"time"
     9  )
    10  
    11  // Bow is a ranged weapon that fires arrows.
    12  type Bow struct{}
    13  
    14  // MaxCount always returns 1.
    15  func (Bow) MaxCount() int {
    16  	return 1
    17  }
    18  
    19  // DurabilityInfo ...
    20  func (Bow) DurabilityInfo() DurabilityInfo {
    21  	return DurabilityInfo{
    22  		MaxDurability: 385,
    23  		BrokenItem:    simpleItem(Stack{}),
    24  	}
    25  }
    26  
    27  // FuelInfo ...
    28  func (Bow) FuelInfo() FuelInfo {
    29  	return newFuelInfo(time.Second * 10)
    30  }
    31  
    32  // Release ...
    33  func (Bow) Release(releaser Releaser, duration time.Duration, ctx *UseContext) {
    34  	creative := releaser.GameMode().CreativeInventory()
    35  	ticks := duration.Milliseconds() / 50
    36  	if ticks < 3 {
    37  		// The player must hold the bow for at least three ticks.
    38  		return
    39  	}
    40  
    41  	d := float64(ticks) / 20
    42  	force := math.Min((d*d+d*2)/3, 1)
    43  	if force < 0.1 {
    44  		// The force must be at least 0.1.
    45  		return
    46  	}
    47  
    48  	arrow, ok := ctx.FirstFunc(func(stack Stack) bool {
    49  		_, ok := stack.Item().(Arrow)
    50  		return ok
    51  	})
    52  	if !ok && !creative {
    53  		// No arrows in inventory and not in creative mode.
    54  		return
    55  	}
    56  
    57  	rot := releaser.Rotation()
    58  	rot = cube.Rotation{-rot[0], -rot[1]}
    59  	if rot[0] > 180 {
    60  		rot[0] = 360 - rot[0]
    61  	}
    62  	var tip potion.Potion
    63  	if !arrow.Empty() {
    64  		// Arrow is empty if not found in the creative inventory.
    65  		tip = arrow.Item().(Arrow).Tip
    66  	}
    67  
    68  	held, _ := releaser.HeldItems()
    69  	damage, punchLevel, burnDuration, consume := 2.0, 0, time.Duration(0), !creative
    70  	for _, enchant := range held.Enchantments() {
    71  		if f, ok := enchant.Type().(interface{ BurnDuration() time.Duration }); ok {
    72  			burnDuration = f.BurnDuration()
    73  		}
    74  		if _, ok := enchant.Type().(interface{ PunchMultiplier(int, float64) float64 }); ok {
    75  			punchLevel = enchant.Level()
    76  		}
    77  		if p, ok := enchant.Type().(interface{ PowerDamage(int) float64 }); ok {
    78  			damage += p.PowerDamage(enchant.Level())
    79  		}
    80  		if i, ok := enchant.Type().(interface{ ConsumesArrows() bool }); ok && !i.ConsumesArrows() {
    81  			consume = false
    82  		}
    83  	}
    84  
    85  	create := releaser.World().EntityRegistry().Config().Arrow
    86  	projectile := create(eyePosition(releaser), releaser.Rotation().Vec3().Mul(force*5), rot, damage, releaser, force >= 1, false, !creative && consume, punchLevel, tip)
    87  	if f, ok := projectile.(interface{ SetOnFire(duration time.Duration) }); ok {
    88  		f.SetOnFire(burnDuration)
    89  	}
    90  
    91  	ctx.DamageItem(1)
    92  	if consume {
    93  		ctx.Consume(arrow.Grow(-arrow.Count() + 1))
    94  	}
    95  
    96  	releaser.PlaySound(sound.BowShoot{})
    97  	releaser.World().AddEntity(projectile)
    98  }
    99  
   100  // EnchantmentValue ...
   101  func (Bow) EnchantmentValue() int {
   102  	return 1
   103  }
   104  
   105  // Requirements returns the required items to release this item.
   106  func (Bow) Requirements() []Stack {
   107  	return []Stack{NewStack(Arrow{}, 1)}
   108  }
   109  
   110  // EncodeItem ...
   111  func (Bow) EncodeItem() (name string, meta int16) {
   112  	return "minecraft:bow", 0
   113  }