26ed99fda6
Build and deploy / Build (push) Has been cancelled
Build and deploy / Update Contributors (push) Has been cancelled
Build and deploy / Deploy (push) Has been cancelled
120 lines
2.9 KiB
Go
120 lines
2.9 KiB
Go
package item
|
|
|
|
import (
|
|
"github.com/df-mc/dragonfly/server/item/potion"
|
|
"github.com/df-mc/dragonfly/server/world"
|
|
"github.com/df-mc/dragonfly/server/world/sound"
|
|
"math"
|
|
"time"
|
|
)
|
|
|
|
// Bow is a ranged weapon that fires arrows.
|
|
type Bow struct{}
|
|
|
|
// MaxCount always returns 1.
|
|
func (Bow) MaxCount() int {
|
|
return 1
|
|
}
|
|
|
|
// DurabilityInfo ...
|
|
func (Bow) DurabilityInfo() DurabilityInfo {
|
|
return DurabilityInfo{
|
|
MaxDurability: 385,
|
|
BrokenItem: simpleItem(Stack{}),
|
|
}
|
|
}
|
|
|
|
// FuelInfo ...
|
|
func (Bow) FuelInfo() FuelInfo {
|
|
return newFuelInfo(time.Second * 10)
|
|
}
|
|
|
|
// Release ...
|
|
func (Bow) Release(releaser Releaser, tx *world.Tx, ctx *UseContext, duration time.Duration) {
|
|
creative := releaser.GameMode().CreativeInventory()
|
|
ticks := duration.Milliseconds() / 50
|
|
if ticks < 3 {
|
|
// The player must hold the bow for at least three ticks.
|
|
return
|
|
}
|
|
|
|
d := float64(ticks) / 20
|
|
force := math.Min((d*d+d*2)/3, 1)
|
|
if force < 0.1 {
|
|
// The force must be at least 0.1.
|
|
return
|
|
}
|
|
|
|
arrow, ok := ctx.FirstFunc(func(stack Stack) bool {
|
|
_, ok := stack.Item().(Arrow)
|
|
return ok
|
|
})
|
|
if !ok && !creative {
|
|
// No arrows in inventory and not in creative mode.
|
|
return
|
|
}
|
|
|
|
var tip potion.Potion
|
|
if !arrow.Empty() {
|
|
// Arrow is empty if not found in the creative inventory.
|
|
tip = arrow.Item().(Arrow).Tip
|
|
}
|
|
|
|
held, _ := releaser.HeldItems()
|
|
damage, punchLevel, burnDuration, consume := 2.0, 0, time.Duration(0), !creative
|
|
for _, enchant := range held.Enchantments() {
|
|
if f, ok := enchant.Type().(interface{ BurnDuration() time.Duration }); ok {
|
|
burnDuration = f.BurnDuration()
|
|
}
|
|
if _, ok := enchant.Type().(interface{ KnockBackMultiplier() float64 }); ok {
|
|
punchLevel = enchant.Level()
|
|
}
|
|
if p, ok := enchant.Type().(interface{ PowerDamage(int) float64 }); ok {
|
|
damage += p.PowerDamage(enchant.Level())
|
|
}
|
|
if i, ok := enchant.Type().(interface{ ConsumesArrows() bool }); ok && !i.ConsumesArrows() {
|
|
consume = false
|
|
}
|
|
}
|
|
|
|
create := tx.World().EntityRegistry().Config().Arrow
|
|
opts := world.EntitySpawnOpts{
|
|
Position: eyePosition(releaser),
|
|
Velocity: releaser.Rotation().Vec3().Mul(force * 5),
|
|
Rotation: releaser.Rotation().Neg(),
|
|
}
|
|
projectile := tx.AddEntity(create(opts, world.ArrowSpawnConfig{
|
|
Damage: damage,
|
|
Owner: releaser,
|
|
Critical: force >= 1,
|
|
ObtainArrowOnPickup: !creative && consume,
|
|
PunchLevel: punchLevel,
|
|
Tip: tip,
|
|
}))
|
|
if f, ok := projectile.(interface{ SetOnFire(duration time.Duration) }); ok {
|
|
f.SetOnFire(burnDuration)
|
|
}
|
|
|
|
ctx.DamageItem(1)
|
|
if consume {
|
|
ctx.Consume(arrow.Grow(-arrow.Count() + 1))
|
|
}
|
|
|
|
tx.PlaySound(releaser.Position(), sound.BowShoot{})
|
|
}
|
|
|
|
// EnchantmentValue ...
|
|
func (Bow) EnchantmentValue() int {
|
|
return 1
|
|
}
|
|
|
|
// Requirements returns the required items to release this item.
|
|
func (Bow) Requirements() []Stack {
|
|
return []Stack{NewStack(Arrow{}, 1)}
|
|
}
|
|
|
|
// EncodeItem ...
|
|
func (Bow) EncodeItem() (name string, meta int16) {
|
|
return "minecraft:bow", 0
|
|
}
|