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 }