github.com/df-mc/dragonfly@v0.9.13/server/block/cactus.go (about)

     1  package block
     2  
     3  import (
     4  	"github.com/df-mc/dragonfly/server/block/cube"
     5  	"github.com/df-mc/dragonfly/server/block/model"
     6  	"github.com/df-mc/dragonfly/server/item"
     7  	"github.com/df-mc/dragonfly/server/world"
     8  	"github.com/df-mc/dragonfly/server/world/particle"
     9  	"github.com/go-gl/mathgl/mgl64"
    10  	"math/rand"
    11  )
    12  
    13  // Cactus is a plant block that generates naturally in dry areas and causes damage.
    14  type Cactus struct {
    15  	transparent
    16  
    17  	// Age is the growth state of cactus. Values range from 0 to 15.
    18  	Age int
    19  }
    20  
    21  // UseOnBlock handles making sure the neighbouring blocks are air.
    22  func (c Cactus) UseOnBlock(pos cube.Pos, face cube.Face, _ mgl64.Vec3, w *world.World, user item.User, ctx *item.UseContext) (used bool) {
    23  	pos, _, used = firstReplaceable(w, pos, face, c)
    24  	if !used {
    25  		return false
    26  	}
    27  	if !c.canGrowHere(pos, w, true) {
    28  		return false
    29  	}
    30  
    31  	place(w, pos, c, user, ctx)
    32  	return placed(ctx)
    33  }
    34  
    35  // NeighbourUpdateTick ...
    36  func (c Cactus) NeighbourUpdateTick(pos, _ cube.Pos, w *world.World) {
    37  	if !c.canGrowHere(pos, w, true) {
    38  		w.SetBlock(pos, nil, nil)
    39  		w.AddParticle(pos.Vec3Centre(), particle.BlockBreak{Block: c})
    40  		dropItem(w, item.NewStack(c, 1), pos.Vec3Centre())
    41  	}
    42  }
    43  
    44  // RandomTick ...
    45  func (c Cactus) RandomTick(pos cube.Pos, w *world.World, _ *rand.Rand) {
    46  	if c.Age < 15 {
    47  		c.Age++
    48  	} else if c.Age == 15 {
    49  		c.Age = 0
    50  		if c.canGrowHere(pos.Side(cube.FaceDown), w, false) {
    51  			for y := 1; y < 3; y++ {
    52  				if _, ok := w.Block(pos.Add(cube.Pos{0, y})).(Air); ok {
    53  					w.SetBlock(pos.Add(cube.Pos{0, y}), Cactus{Age: 0}, nil)
    54  					break
    55  				} else if _, ok := w.Block(pos.Add(cube.Pos{0, y})).(Cactus); !ok {
    56  					break
    57  				}
    58  			}
    59  		}
    60  	}
    61  	w.SetBlock(pos, c, nil)
    62  }
    63  
    64  // canGrowHere implements logic to check if cactus can live/grow here.
    65  func (c Cactus) canGrowHere(pos cube.Pos, w *world.World, recursive bool) bool {
    66  	for _, face := range cube.HorizontalFaces() {
    67  		if _, ok := w.Block(pos.Side(face)).(Air); !ok {
    68  			return false
    69  		}
    70  	}
    71  	if _, ok := w.Block(pos.Side(cube.FaceDown)).(Cactus); ok && recursive {
    72  		return c.canGrowHere(pos.Side(cube.FaceDown), w, recursive)
    73  	}
    74  	return supportsVegetation(c, w.Block(pos.Sub(cube.Pos{0, 1})))
    75  }
    76  
    77  // EntityInside ...
    78  func (c Cactus) EntityInside(_ cube.Pos, _ *world.World, e world.Entity) {
    79  	if l, ok := e.(livingEntity); ok && !l.AttackImmune() {
    80  		l.Hurt(0.5, DamageSource{Block: c})
    81  	}
    82  }
    83  
    84  // BreakInfo ...
    85  func (c Cactus) BreakInfo() BreakInfo {
    86  	return newBreakInfo(0.4, alwaysHarvestable, nothingEffective, oneOf(c))
    87  }
    88  
    89  // CompostChance ...
    90  func (Cactus) CompostChance() float64 {
    91  	return 0.5
    92  }
    93  
    94  // EncodeItem ...
    95  func (c Cactus) EncodeItem() (name string, meta int16) {
    96  	return "minecraft:cactus", 0
    97  }
    98  
    99  // EncodeBlock ...
   100  func (c Cactus) EncodeBlock() (name string, properties map[string]any) {
   101  	return "minecraft:cactus", map[string]any{"age": int32(c.Age)}
   102  }
   103  
   104  // Model ...
   105  func (c Cactus) Model() world.BlockModel {
   106  	return model.Cactus{}
   107  }
   108  
   109  // allCactus returns all possible states of a cactus block.
   110  func allCactus() (b []world.Block) {
   111  	for i := 0; i < 16; i++ {
   112  		b = append(b, Cactus{Age: i})
   113  	}
   114  	return
   115  }
   116  
   117  // DamageSource is passed as world.DamageSource for damage caused by a block,
   118  // such as a cactus or a falling anvil.
   119  type DamageSource struct {
   120  	// Block is the block that caused the damage.
   121  	Block world.Block
   122  }
   123  
   124  func (DamageSource) ReducedByResistance() bool { return true }
   125  func (DamageSource) ReducedByArmour() bool     { return true }
   126  func (DamageSource) Fire() bool                { return false }