Skip to content

Commit

Permalink
item/enchantment: Implemented thorns enchantment (#553)
Browse files Browse the repository at this point in the history
Co-authored-by: DaPigGuy <mcpepig123@gmail.com>
  • Loading branch information
HashimTheArab and DaPigGuy committed Jul 16, 2022
1 parent ff76b6f commit 8e87a7f
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 2 deletions.
12 changes: 11 additions & 1 deletion server/entity/damage/source.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package damage

import "github.com/df-mc/dragonfly/server/world"
import (
"github.com/df-mc/dragonfly/server/world"
)

type (
// Source represents the source of the damage dealt to an entity. This source may be passed to the Hurt()
Expand Down Expand Up @@ -68,6 +70,12 @@ type (
Projectile, Owner world.Entity
}

// SourceThorns is used for damage caused by thorns.
SourceThorns struct {
// Owner holds the entity wearing the thorns armour.
Owner world.Entity
}

// SourceBlock is used for damage caused by a block, such as an anvil.
SourceBlock struct {
// Block is the block that caused the damage.
Expand Down Expand Up @@ -103,5 +111,7 @@ func (SourceLava) ReducedByResistance() bool { return true }
func (SourceLava) ReducedByArmour() bool { return true }
func (SourceProjectile) ReducedByResistance() bool { return true }
func (SourceProjectile) ReducedByArmour() bool { return true }
func (SourceThorns) ReducedByResistance() bool { return true }
func (SourceThorns) ReducedByArmour() bool { return false }
func (SourceBlock) ReducedByResistance() bool { return true }
func (SourceBlock) ReducedByArmour() bool { return true }
2 changes: 1 addition & 1 deletion server/item/enchantment/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ func init() {
item.RegisterEnchantment(2, FeatherFalling{})
// TODO: (3) Blast Protection.
item.RegisterEnchantment(4, ProjectileProtection{})
// TODO: (5) Thorns.
item.RegisterEnchantment(5, Thorns{})
item.RegisterEnchantment(6, Respiration{})
item.RegisterEnchantment(7, DepthStrider{})
item.RegisterEnchantment(8, AquaAffinity{})
Expand Down
35 changes: 35 additions & 0 deletions server/item/enchantment/thorns.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package enchantment

import (
"github.com/df-mc/dragonfly/server/item"
"github.com/df-mc/dragonfly/server/world"
)

// Thorns is an enchantment that inflicts damage on attackers.
type Thorns struct{}

// Name ...
func (Thorns) Name() string {
return "Thorns"
}

// MaxLevel ...
func (Thorns) MaxLevel() int {
return 3
}

// Rarity ...
func (Thorns) Rarity() item.EnchantmentRarity {
return item.EnchantmentRarityVeryRare
}

// CompatibleWithEnchantment ...
func (Thorns) CompatibleWithEnchantment(item.EnchantmentType) bool {
return true
}

// CompatibleWithItem ...
func (Thorns) CompatibleWithItem(i world.Item) bool {
_, ok := i.(item.Armour)
return ok
}
30 changes: 30 additions & 0 deletions server/player/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/df-mc/dragonfly/server/world/sound"
"github.com/go-gl/mathgl/mgl64"
"github.com/google/uuid"
"golang.org/x/exp/maps"
"golang.org/x/text/language"
"math"
"math/rand"
Expand Down Expand Up @@ -557,11 +558,40 @@ func (p *Player) Hurt(dmg float64, source damage.Source) (float64, bool) {
p.Exhaust(0.1)

damageToArmour := int(math.Max(math.Floor(dmg/4), 1))
var damageToAttacker int
thornsArmour := map[int]item.Stack{}
for slot, it := range p.armour.Slots() {
if _, ok := it.Item().(item.Durable); ok {
if e, ok := it.Enchantment(enchantment.Thorns{}); ok && rand.Float64() < float64(e.Level())*0.15 {
damageToArmour++
thornsArmour[slot] = it
if e.Level() > 10 {
damageToAttacker += e.Level() - 10
} else {
damageToAttacker += 1 + rand.Intn(4)
}
}
_ = p.armour.Inventory().SetItem(slot, p.damageItem(it, damageToArmour))
}
}

if length := len(thornsArmour); length > 0 {
slot := maps.Keys(thornsArmour)[rand.Intn(length)]
item := thornsArmour[slot]

_ = p.armour.Inventory().SetItem(slot, p.damageItem(item, 2))
if damageToAttacker > 0 {
var attacker world.Entity
if s, ok := source.(damage.SourceEntityAttack); ok {
attacker = s.Attacker
} else if s, ok := source.(damage.SourceProjectile); ok {
attacker = s.Owner
}
if l, ok := attacker.(entity.Living); ok {
l.Hurt(float64(damageToAttacker), damage.SourceThorns{Owner: attacker})
}
}
}
}

w, pos := p.World(), p.Position()
Expand Down

0 comments on commit 8e87a7f

Please sign in to comment.