up3
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
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
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/df-mc/dragonfly/server/block/cube"
|
||||
"github.com/df-mc/dragonfly/server/world"
|
||||
"github.com/df-mc/dragonfly/server/world/sound"
|
||||
"github.com/go-gl/mathgl/mgl64"
|
||||
"math/rand/v2"
|
||||
"time"
|
||||
)
|
||||
|
||||
// NewLightning creates a lightning entity. The lightning entity will be
|
||||
// positioned at the position passed. Lightning is a lethal element to
|
||||
// thunderstorms. Lightning momentarily increases the skylight's brightness to
|
||||
// slightly greater than full daylight.
|
||||
func NewLightning(opts world.EntitySpawnOpts) *world.EntityHandle {
|
||||
return NewLightningWithDamage(opts, 5, true, time.Second*8)
|
||||
}
|
||||
|
||||
// NewLightningWithDamage creates a new lightning entities using the damage and
|
||||
// fire properties passed.
|
||||
func NewLightningWithDamage(opts world.EntitySpawnOpts, dmg float64, blockFire bool, entityFireDuration time.Duration) *world.EntityHandle {
|
||||
conf := lightningConf
|
||||
conf.Tick = (&lightningState{
|
||||
Damage: dmg,
|
||||
EntityFireDuration: entityFireDuration,
|
||||
BlockFire: blockFire,
|
||||
state: 2,
|
||||
lifetime: rand.IntN(4) + 1,
|
||||
}).tick
|
||||
return opts.New(LightningType, conf)
|
||||
}
|
||||
|
||||
var lightningConf = StationaryBehaviourConfig{SpawnSounds: []world.Sound{sound.Explosion{}, sound.Thunder{}}, ExistenceDuration: time.Second}
|
||||
|
||||
// lightningState holds the state of a lightning entity.
|
||||
type lightningState struct {
|
||||
Damage float64
|
||||
EntityFireDuration time.Duration
|
||||
BlockFire bool
|
||||
state, lifetime int
|
||||
}
|
||||
|
||||
// tick carries out lightning logic, dealing damage and setting blocks/entities
|
||||
// on fire when appropriate.
|
||||
func (s *lightningState) tick(e *Ent, tx *world.Tx) {
|
||||
pos := e.Position()
|
||||
|
||||
if s.state--; s.state < 0 {
|
||||
if s.lifetime == 0 {
|
||||
_ = e.Close()
|
||||
} else if s.state < -rand.IntN(10) {
|
||||
s.lifetime--
|
||||
s.state = 1
|
||||
|
||||
if s.BlockFire && tx.World().Difficulty().FireSpreadIncrease() >= 10 {
|
||||
s.spreadFire(tx, cube.PosFromVec3(pos))
|
||||
}
|
||||
}
|
||||
}
|
||||
if s.state > 0 {
|
||||
s.dealDamage(e, tx)
|
||||
}
|
||||
}
|
||||
|
||||
// dealDamage deals damage to all entities around the lightning and sets them
|
||||
// on fire.
|
||||
func (s *lightningState) dealDamage(e *Ent, tx *world.Tx) {
|
||||
pos := e.Position()
|
||||
bb := e.H().Type().BBox(e).GrowVec3(mgl64.Vec3{3, 6, 3}).Translate(pos.Add(mgl64.Vec3{0, 3}))
|
||||
for e := range tx.EntitiesWithin(bb) {
|
||||
// Only damage entities that weren't already dead.
|
||||
if l, ok := e.(Living); ok && l.Health() > 0 {
|
||||
if s.Damage > 0 {
|
||||
l.Hurt(s.Damage, LightningDamageSource{})
|
||||
}
|
||||
if f, ok := e.(Flammable); ok && f.OnFireDuration() < s.EntityFireDuration {
|
||||
f.SetOnFire(s.EntityFireDuration)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// spreadFire attempts to place fire at the position of the lightning and does
|
||||
// 4 additional attempts to spread it around that position.
|
||||
func (s *lightningState) spreadFire(tx *world.Tx, pos cube.Pos) {
|
||||
s.fire().Start(tx, pos)
|
||||
for i := 0; i < 4; i++ {
|
||||
pos.Add(cube.Pos{rand.IntN(3) - 1, rand.IntN(3) - 1, rand.IntN(3) - 1})
|
||||
s.fire().Start(tx, pos)
|
||||
}
|
||||
}
|
||||
|
||||
// fire returns a fire block.
|
||||
func (s *lightningState) fire() interface {
|
||||
Start(tx *world.Tx, pos cube.Pos)
|
||||
} {
|
||||
return fire().(interface {
|
||||
Start(tx *world.Tx, pos cube.Pos)
|
||||
})
|
||||
}
|
||||
|
||||
// fire returns a fire block.
|
||||
func fire() world.Block {
|
||||
f, ok := world.BlockByName("minecraft:fire", map[string]any{"age": int32(0)})
|
||||
if !ok {
|
||||
panic("could not find fire block")
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// LightningType is a world.EntityType implementation for Lightning.
|
||||
var LightningType lightningType
|
||||
|
||||
type lightningType struct{}
|
||||
|
||||
func (t lightningType) Open(tx *world.Tx, handle *world.EntityHandle, data *world.EntityData) world.Entity {
|
||||
return &Ent{tx: tx, handle: handle, data: data}
|
||||
}
|
||||
func (t lightningType) DecodeNBT(_ map[string]any, data *world.EntityData) {
|
||||
data.Data = lightningConf.New()
|
||||
}
|
||||
func (t lightningType) EncodeNBT(*world.EntityData) map[string]any { return nil }
|
||||
func (lightningType) EncodeEntity() string { return "minecraft:lightning_bolt" }
|
||||
func (lightningType) BBox(world.Entity) cube.BBox { return cube.BBox{} }
|
||||
Reference in New Issue
Block a user