package block import ( "math" "math/rand/v2" "github.com/df-mc/dragonfly/server/block/cube" "github.com/df-mc/dragonfly/server/item" "github.com/df-mc/dragonfly/server/world" "github.com/go-gl/mathgl/mgl64" ) // SeaPickle is a small stationary underwater block that emits light, and is typically found in colonies of up to // four sea pickles. type SeaPickle struct { empty transparent sourceWaterDisplacer // AdditionalCount is the amount of additional sea pickles clustered together. AdditionalCount int // Dead is whether the sea pickles are not alive. Sea pickles are only considered alive when inside of water. While // alive, sea pickles emit light & can be grown with bone meal. Dead bool } // canSurvive ... func (SeaPickle) canSurvive(pos cube.Pos, tx *world.Tx) bool { below := tx.Block(pos.Side(cube.FaceDown)) if !below.Model().FaceSolid(pos.Side(cube.FaceDown), cube.FaceUp, tx) { return false } if liquid, ok := tx.Liquid(pos); ok { if _, ok = liquid.(Water); !ok || liquid.LiquidDepth() != 8 { return false } } if emitter, ok := below.(LightDiffuser); ok && emitter.LightDiffusionLevel() != 15 { return false } return true } // BoneMeal ... func (s SeaPickle) BoneMeal(pos cube.Pos, tx *world.Tx) item.BoneMealResult { if s.Dead { return item.BoneMealResultNone } if coral, ok := tx.Block(pos.Side(cube.FaceDown)).(CoralBlock); !ok || coral.Dead { return item.BoneMealResultNone } if s.AdditionalCount != 3 { s.AdditionalCount = 3 tx.SetBlock(pos, s, nil) } for x := -2; x <= 2; x++ { distance := -int(math.Abs(float64(x))) + 2 for z := -distance; z <= distance; z++ { for y := -1; y < 1; y++ { if (x == 0 && y == 0 && z == 0) || rand.IntN(6) != 0 { continue } newPos := pos.Add(cube.Pos{x, y, z}) if _, ok := tx.Block(newPos).(Water); !ok { continue } if coral, ok := tx.Block(newPos.Side(cube.FaceDown)).(CoralBlock); !ok || coral.Dead { continue } tx.SetBlock(newPos, SeaPickle{AdditionalCount: rand.IntN(3) + 1}, nil) } } } return item.BoneMealResultSmall } // UseOnBlock ... func (s SeaPickle) UseOnBlock(pos cube.Pos, face cube.Face, _ mgl64.Vec3, tx *world.Tx, user item.User, ctx *item.UseContext) bool { if existing, ok := tx.Block(pos).(SeaPickle); ok { if existing.AdditionalCount >= 3 { return false } existing.AdditionalCount++ place(tx, pos, existing, user, ctx) return placed(ctx) } pos, _, used := firstReplaceable(tx, pos, face, s) if !used { return false } if !s.canSurvive(pos, tx) { return false } s.Dead = true if liquid, ok := tx.Liquid(pos); ok { _, ok = liquid.(Water) s.Dead = !ok } place(tx, pos, s, user, ctx) return placed(ctx) } // NeighbourUpdateTick ... func (s SeaPickle) NeighbourUpdateTick(pos, _ cube.Pos, tx *world.Tx) { if !s.canSurvive(pos, tx) { breakBlock(s, pos, tx) return } alive := false if liquid, ok := tx.Liquid(pos); ok { _, alive = liquid.(Water) } if s.Dead == alive { s.Dead = !alive tx.SetBlock(pos, s, nil) } } // HasLiquidDrops ... func (SeaPickle) HasLiquidDrops() bool { return true } // SideClosed ... func (SeaPickle) SideClosed(cube.Pos, cube.Pos, *world.Tx) bool { return false } // LightEmissionLevel ... func (s SeaPickle) LightEmissionLevel() uint8 { if s.Dead { return 0 } return uint8(6 + s.AdditionalCount*3) } // BreakInfo ... func (s SeaPickle) BreakInfo() BreakInfo { return newBreakInfo(0, alwaysHarvestable, nothingEffective, simpleDrops(item.NewStack(s, s.AdditionalCount+1))) } // FlammabilityInfo ... func (SeaPickle) FlammabilityInfo() FlammabilityInfo { return newFlammabilityInfo(15, 100, true) } // SmeltInfo ... func (SeaPickle) SmeltInfo() item.SmeltInfo { return newSmeltInfo(item.NewStack(item.Dye{Colour: item.ColourLime()}, 1), 0.1) } // CompostChance ... func (SeaPickle) CompostChance() float64 { return 0.65 } // EncodeItem ... func (SeaPickle) EncodeItem() (name string, meta int16) { return "minecraft:sea_pickle", 0 } // EncodeBlock ... func (s SeaPickle) EncodeBlock() (string, map[string]any) { return "minecraft:sea_pickle", map[string]any{"cluster_count": int32(s.AdditionalCount), "dead_bit": s.Dead} } // allSeaPickles ... func allSeaPickles() (b []world.Block) { for i := 0; i <= 3; i++ { b = append(b, SeaPickle{AdditionalCount: i}) b = append(b, SeaPickle{AdditionalCount: i, Dead: true}) } return }