Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement totems #858

Merged
merged 10 commits into from
Apr 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions server/entity/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ type PickedUpAction struct {
// FireworkExplosionAction is a world.EntityAction that makes a Firework rocket display an explosion particle.
type FireworkExplosionAction struct{ action }

// TotemUseAction is a world.EntityAction that displays the totem use particles and animation.
type TotemUseAction struct{ action }

// action implements the Action interface. Structures in this package may embed it to gets its functionality
// out of the box.
type action struct{}
Expand Down
1 change: 1 addition & 0 deletions server/item/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ func init() {
world.RegisterItem(Spyglass{})
world.RegisterItem(Stick{})
world.RegisterItem(Sugar{})
world.RegisterItem(Totem{})
world.RegisterItem(TropicalFish{})
world.RegisterItem(TurtleShell{})
world.RegisterItem(WarpedFungusOnAStick{})
Expand Down
14 changes: 14 additions & 0 deletions server/item/totem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package item

// Totem is an uncommon combat item that can save holders from death.
type Totem struct{}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd just document this struct, explain what the item is. Doesn't need to be much


// MaxCount always returns 1.
func (Totem) MaxCount() int {
return 1
}

// EncodeItem ...
func (Totem) EncodeItem() (name string, meta int16) {
return "minecraft:totem_of_undying", 0
}
34 changes: 34 additions & 0 deletions server/player/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -584,9 +584,24 @@ func (p *Player) Hurt(dmg float64, src world.DamageSource) (float64, bool) {
damageLeft -= a
} else {
p.SetAbsorption(a - damageLeft)

damageLeft = 0
}
}

if p.Health()-damageLeft <= mgl64.Epsilon {
hand, offHand := p.HeldItems()
if _, ok := offHand.Item().(item.Totem); ok {
p.applyTotemEffects()
p.SetHeldItems(hand, offHand.Grow(-1))
return 0, false
} else if _, ok := hand.Item().(item.Totem); ok {
p.applyTotemEffects()
p.SetHeldItems(hand.Grow(-1), offHand)
return 0, false
}
}

p.addHealth(-damageLeft)

if src.ReducedByArmour() {
Expand Down Expand Up @@ -623,6 +638,25 @@ func (p *Player) Hurt(dmg float64, src world.DamageSource) (float64, bool) {
return totalDamage, true
}

// applyTotemEffects is an unexported function that is used to handle totem effects.
func (p *Player) applyTotemEffects() {
p.addHealth(2 - p.Health())

for _, e := range p.Effects() {
p.RemoveEffect(e.Type())
}

p.AddEffect(effect.New(effect.Regeneration{}, 2, time.Second*40))
p.AddEffect(effect.New(effect.FireResistance{}, 1, time.Second*40))
p.AddEffect(effect.New(effect.Absorption{}, 2, time.Second*5))

p.World().PlaySound(p.Position(), sound.Totem{})

for _, viewer := range p.viewers() {
viewer.ViewEntityAction(p, entity.TotemUseAction{})
}
}

// FinalDamageFrom resolves the final damage received by the player if it is attacked by the source passed
// with the damage passed. FinalDamageFrom takes into account things such as the armour worn and the
// enchantments on the individual pieces.
Expand Down
10 changes: 10 additions & 0 deletions server/session/world.go
Original file line number Diff line number Diff line change
Expand Up @@ -771,6 +771,11 @@ func (s *Session) playSound(pos mgl64.Vec3, t world.Sound, disableRelative bool)
pk.SoundType = packet.SoundEventComposterReady
case sound.LecternBookPlace:
pk.SoundType = packet.SoundEventLecternBookPlace
case sound.Totem:
s.writePacket(&packet.LevelEvent{
EventType: packet.LevelEventSoundTotemUsed,
Position: vec64To32(pos),
})
}
s.writePacket(pk)
}
Expand Down Expand Up @@ -914,6 +919,11 @@ func (s *Session) ViewEntityAction(e world.Entity, a world.EntityAction) {
EventData: (rid << 16) | int32(meta),
})
}
case entity.TotemUseAction:
s.writePacket(&packet.ActorEvent{
EntityRuntimeID: s.entityRuntimeID(e),
EventType: packet.ActorEventTalismanActivate,
})
}
}

Expand Down
3 changes: 3 additions & 0 deletions server/world/sound/item.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,6 @@ type GoatHorn struct {
// FireCharge is a sound played when a player lights a block on fire with a fire charge, or when a dispenser or a
// blaze shoots a fireball.
type FireCharge struct{ sound }

// Totem is a sound played when a player uses a totem.
type Totem struct{ sound }
Loading