Skip to content

Commit

Permalink
feat: add Malignant Bloom and Sapberry
Browse files Browse the repository at this point in the history
  • Loading branch information
Elenterius committed Sep 21, 2023
1 parent 633c014 commit 6d575d2
Show file tree
Hide file tree
Showing 39 changed files with 2,872 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ private void addItemTranslations() {
addItem(ModItems.NUTRIENTS, "Nutrients", "Very hard pellets rich in energy that almost look like vitamin pills.");
addItem(ModItems.NUTRIENT_PASTE, "Nutrient Paste", "Nutrients combined with Biotic Matter to moisten the hard pellets, producing a paste.\nIt almost looks like yellowish cake, and is a convenient source of energy.");
addItem(ModItems.NUTRIENT_BAR, "Nutrient Bar", "Nutrient Paste compressed into the shape of a bar. Looks edible, if a bit bland.");
addItem(ModItems.SAPBERRY, "Sapberry", "An exotic delicacy which grants random potion effects.");

addItem(ModItems.REGENERATIVE_FLUID, "Regenerative Fluid", "A fluid with regenerative properties, used to concoct healing additives.");
addItem(ModItems.WITHERING_OOZE, "Withering Ooze", "A corrosive extract. It likely has uses in bio-alchemy.");
Expand Down Expand Up @@ -496,6 +497,7 @@ private void addBlockTranslations() {
addBlock(ModBlocks.MALIGNANT_FLESH_STAIRS, "Malignant Flesh Stairs", "Stairs made of malignant flesh.\nLooks diseased...");
addBlock(ModBlocks.MALIGNANT_FLESH_WALL, "Malignant Flesh Wall", "Wall of malignant flesh.\nIt's coming for you! ;)");
addBlock(ModBlocks.MALIGNANT_FLESH_VEINS, "Malignant Flesh Veins", "They look almost feral...\nyou better not touch them.");
addBlock(ModBlocks.MALIGNANT_BLOOM, "Malignant Bloom", "An exotic flower of primordial beauty.\n\nIt will spread itself by launching it's ripe berry into the air.\nOn impact the berry explodes and spreads malignant veins as well.");
}

private void addEntityTranslations() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ protected void addTables() {
dropSelf(ModBlocks.MALIGNANT_FLESH_STAIRS.get());
dropSelf(ModBlocks.MALIGNANT_FLESH_WALL.get());
add(ModBlocks.MALIGNANT_FLESH_VEINS.get(), block -> createMultifaceBlockDrops(block, HAS_SHEARS_OR_SILK_TOUCH));
add(ModBlocks.MALIGNANT_BLOOM.get(), noDrop());

dropSelf(ModBlocks.VOICE_BOX.get());
dropSelf(ModBlocks.IMPERMEABLE_MEMBRANE.get());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.github.elenterius.biomancy.BiomancyMod;
import com.github.elenterius.biomancy.block.*;
import com.github.elenterius.biomancy.block.fleshspike.FleshSpikeBlock;
import com.github.elenterius.biomancy.block.malignantbloom.MalignantBloomBlock;
import com.github.elenterius.biomancy.block.ownable.OwnablePressurePlateBlock;
import com.github.elenterius.biomancy.block.property.DirectionalSlabType;
import com.github.elenterius.biomancy.block.property.Orientation;
Expand Down Expand Up @@ -89,6 +90,7 @@ protected void registerStatesAndModels() {
stairsBlockWithItem(ModBlocks.MALIGNANT_FLESH_STAIRS, ModBlocks.MALIGNANT_FLESH);
wallBlock(ModBlocks.MALIGNANT_FLESH_WALL, ModBlocks.MALIGNANT_FLESH);
veinsBlock(ModBlocks.MALIGNANT_FLESH_VEINS);
malignantBloom(ModBlocks.MALIGNANT_BLOOM);

irisDoor(ModBlocks.FLESH_IRIS_DOOR, true);
fleshDoor(ModBlocks.FLESH_DOOR);
Expand Down Expand Up @@ -309,6 +311,26 @@ public void directionalBlock(Block block, Function<BlockState, ModelFile> modelF
}, ignored);
}

public <T extends MalignantBloomBlock> void malignantBloom(RegistryObject<T> block) {
malignantBloom(block.get());
}

public void malignantBloom(MalignantBloomBlock block) {
ResourceLocation model = blockAsset(block);

ModelFile.ExistingModelFile[] models = {
models().getExistingFile(extend(model, "_1")),
models().getExistingFile(extend(model, "_2")),
models().getExistingFile(extend(model, "_3")),
models().getExistingFile(extend(model, "_4")),
models().getExistingFile(extend(model, "_5"))
};

directionalBlock(block, blockState -> models[MalignantBloomBlock.getStage(blockState)], BlockStateProperties.WATERLOGGED);

simpleBlockItem(block, models[0]);
}

public void fleshSpikes(Block block) {
ResourceLocation model = blockAsset(block);
ModelFile.ExistingModelFile[] models = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ protected void registerModels() {
basicItem(ModItems.CREATOR_MIX);
basicItem(ModItems.NUTRIENT_PASTE);
basicItem(ModItems.NUTRIENT_BAR);
basicItem(ModItems.SAPBERRY);
serumItem(ModItems.VIAL);
basicItem(ModItems.GIFT_SAC);
basicItem(ModItems.FERTILIZER);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,12 @@ private void registerDecomposingRecipes(Consumer<FinishedRecipe> consumer) {
.addOutput(ModItems.FLESH_BITS.get(), 3, 6)
.addOutput(ModItems.EXOTIC_DUST.get(), 0, 2)
.unlockedBy(ModItems.LIVING_FLESH).save(consumer);
DecomposerRecipeBuilder.create().setIngredient(ModItems.SAPBERRY)
.addOutput(ModItems.BIO_LUMENS.get(), 0, 2)
.addOutput(ModItems.ORGANIC_MATTER.get(), 0, 1)
.addOutput(ModItems.EXOTIC_DUST.get(), 0, 3)
.addOutput(ModItems.BILE.get(), 1, 2)
.unlockedBy(ModItems.SAPBERRY).save(consumer);

registerDecomposerRecipesFor119(consumer);
registerDecomposerRecipesForBiomesOPlenty(consumer);
Expand Down
4 changes: 4 additions & 0 deletions src/generated/resources/assets/biomancy/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
"item.biomancy.nutrient_paste.tooltip": "Nutrients combined with Biotic Matter to moisten the hard pellets, producing a paste.\nIt almost looks like yellowish cake, and is a convenient source of energy.",
"item.biomancy.nutrient_bar": "Nutrient Bar",
"item.biomancy.nutrient_bar.tooltip": "Nutrient Paste compressed into the shape of a bar. Looks edible, if a bit bland.",
"item.biomancy.sapberry": "Sapberry",
"item.biomancy.sapberry.tooltip": "An exotic delicacy which grants random potion effects.",
"item.biomancy.regenerative_fluid": "Regenerative Fluid",
"item.biomancy.regenerative_fluid.tooltip": "A fluid with regenerative properties, used to concoct healing additives.",
"item.biomancy.withering_ooze": "Withering Ooze",
Expand Down Expand Up @@ -225,6 +227,8 @@
"block.biomancy.malignant_flesh_wall.tooltip": "Wall of malignant flesh.\nIt's coming for you! ;)",
"block.biomancy.malignant_flesh_veins": "Malignant Flesh Veins",
"block.biomancy.malignant_flesh_veins.tooltip": "They look almost feral...\nyou better not touch them.",
"block.biomancy.malignant_bloom": "Malignant Bloom",
"block.biomancy.malignant_bloom.tooltip": "An exotic flower of primordial beauty.\n\nIt will spread itself by launching it's ripe berry into the air.\nOn impact the berry explodes and spreads malignant veins as well.",
"entity.biomancy.hungry_flesh_blob": "Hungry Flesh Blob",
"entity.biomancy.flesh_blob": "Flesh Blob",
"entity.biomancy.legacy_flesh_blob": "Legacy Flesh Blob",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,19 @@ public BlockState getStateForPlacement(BlockPlaceContext context) {
return defaultBlockState().setValue(TYPE, type).setValue(WATERLOGGED, isWaterlogged);
}

public BlockState getStateForPlacement(BlockGetter level, BlockPos pos, Direction direction) {
BlockState state = level.getBlockState(pos);
boolean isWaterlogged = level.getFluidState(pos).getType() == Fluids.WATER;

if (state.is(this) && state.getValue(TYPE) != DirectionalSlabType.FULL) {
return defaultBlockState().setValue(TYPE, DirectionalSlabType.FULL).setValue(WATERLOGGED, false);
}

DirectionalSlabType type = DirectionalSlabType.getHalfFrom(direction);

return defaultBlockState().setValue(TYPE, type).setValue(WATERLOGGED, isWaterlogged);
}

@Override
public boolean canBeReplaced(BlockState state, BlockPlaceContext useContext) {
ItemStack stack = useContext.getItemInHand();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ public void onSacrifice(ServerLevel level) {
SoundUtil.broadcastBlockSound(level, pos, ModSoundEvents.FLESH_BLOCK_STEP.get(), 1f, 0.15f + level.random.nextFloat() * 0.5f);
}

//primalSpreadCharge = Integer.MAX_VALUE; //uncomment to unleash the abomination

resetState();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ final class Tributes {
.put(ModItems.CREATOR_MIX.get(), Tribute.builder().biomass(20).lifeEnergy(20).successModifier(19).diseaseModifier(6).hostileModifier(-12).create())
.put(ModItems.PRIMORDIAL_CORE.get(), Tribute.builder().biomass(80).successModifier(64).anomalyModifier(100).diseaseModifier(50).create())
.put(ModItems.LIVING_FLESH.get(), Tribute.builder().biomass(10).lifeEnergy(10).successModifier(40).anomalyModifier(55).create())
.put(ModItems.SAPBERRY.get(), Tribute.builder().successModifier(10).lifeEnergy(20).anomalyModifier(20).create())
.put(Items.GOLDEN_APPLE, Tribute.builder().successModifier(10).hostileModifier(-100).create())
.put(Items.ENCHANTED_GOLDEN_APPLE, Tribute.builder().lifeEnergy(15).successModifier(40).hostileModifier(-200).create())
.put(Items.CAKE, Tribute.builder().hostileModifier(-80).diseaseModifier(10).create())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
package com.github.elenterius.biomancy.block.malignantbloom;

import com.github.elenterius.biomancy.block.base.WaterloggedFacingBlock;
import com.github.elenterius.biomancy.init.ModBlocks;
import com.github.elenterius.biomancy.init.ModItems;
import com.github.elenterius.biomancy.init.ModPlantTypes;
import com.github.elenterius.biomancy.init.ModProjectiles;
import com.github.elenterius.biomancy.util.EnhancedIntegerProperty;
import com.github.elenterius.biomancy.world.PrimordialEcosystem;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.common.IPlantable;
import net.minecraftforge.common.PlantType;

public class MalignantBloomBlock extends WaterloggedFacingBlock implements IPlantable {

public static final EnhancedIntegerProperty AGE = EnhancedIntegerProperty.wrap(BlockStateProperties.AGE_7);

public MalignantBloomBlock(Properties properties) {
super(properties);
registerDefaultState(defaultBlockState().setValue(AGE.get(), AGE.getMin()));
MalignantBloomShapes.computePossibleShapes(stateDefinition.getPossibleStates());
}

public static int getAge(BlockState state) {
return AGE.getValue(state);
}

public static int getStage(BlockState state) {
return getStageFromAge(AGE.getValue(state));
}

public static int getStageFromAge(int age) {
int[] stages = {0, 0, 1, 1, 2, 2, 3, 4};

age = Mth.clamp(age, 0, 7);
return stages[age];
}

private static int getGrowthSpeed(ServerLevel level, BlockPos pos) {
int veins = PrimordialEcosystem.countMalignantVeinsAroundPos(level, pos);
int maxVeins = 3 * 3 * 3 - 1;
return Math.max(maxVeins - veins, 0) + 1;
}

public static int getLightEmission(BlockState state) {
int age = getAge(state);
if (age < 6) return 0;
if (age < 7) return 10;
return 12;
}

@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(AGE.get());
}

public BlockState getStateForPlacement(BlockGetter level, BlockPos pos, Direction direction) {
boolean isWaterlogged = level.getFluidState(pos).getType() == Fluids.WATER;
return defaultBlockState().setValue(FACING, direction).setValue(WATERLOGGED, isWaterlogged);
}

@Override
public boolean isRandomlyTicking(BlockState state) {
return true;
}

@Override
public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (!level.isAreaLoaded(pos, 1)) return;

int age = AGE.getValue(state);
if (age < AGE.getMax()) {
int growthSpeed = age < AGE.getMax() - 1 ? getGrowthSpeed(level, pos) : 1;

if (ForgeHooks.onCropsGrowPre(level, pos, state, random.nextInt(growthSpeed) == 0)) {
level.setBlock(pos, AGE.addValue(state, 1), Block.UPDATE_CLIENTS);
ForgeHooks.onCropsGrowPost(level, pos, state);
}
}
else {
Direction direction = getFacing(state);

level.sendParticles(ParticleTypes.EXPLOSION, pos.getX() + 0.5d, pos.getY() + 0.5d, pos.getZ() + 0.5d, 1, 0, 0, 0, 0);
level.setBlock(pos, AGE.setValue(state, AGE.getMin()), Block.UPDATE_CLIENTS);

BlockPos target = pos.relative(direction, 10).offset(random.nextIntBetweenInclusive(-5, 5), random.nextIntBetweenInclusive(-5, 5), random.nextIntBetweenInclusive(-5, 5));
ModProjectiles.SAPBERRY.shoot(level, Vec3.atCenterOf(pos), Vec3.atCenterOf(target));
}
}

@Override
public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
int age = AGE.getValue(state);
if (age > 5 && player.getItemInHand(hand).isEmpty()) {
if (!level.isClientSide) {
int count = 1 + (age > 6 ? level.random.nextInt(2) : 0);
popResource(level, pos, new ItemStack(ModItems.SAPBERRY.get(), count));

player.hurt(DamageSource.SWEET_BERRY_BUSH, 1.0F);

level.playSound(null, pos, SoundEvents.CAVE_VINES_PICK_BERRIES, SoundSource.BLOCKS, 1f, 0.5f + level.random.nextFloat() * 0.4f);
BlockState blockState = AGE.setValue(state, AGE.getMin());
level.setBlock(pos, blockState, Block.UPDATE_CLIENTS);
level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(player, blockState));
}

return InteractionResult.sidedSuccess(level.isClientSide);
}

return super.use(state, level, pos, player, hand, hit);
}

@Override
public BlockState getPlant(BlockGetter level, BlockPos pos) {
BlockState state = level.getBlockState(pos);
if (state.getBlock() != this) return defaultBlockState();
return state;
}

@Override
public PlantType getPlantType(BlockGetter level, BlockPos pos) {
return ModPlantTypes.FLESH_PLANT_TYPE;
}

@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos currentPos, BlockPos neighborPos) {
return !state.canSurvive(level, currentPos) ? Blocks.AIR.defaultBlockState() : super.updateShape(state, direction, neighborState, level, currentPos, neighborPos);
}

public boolean mayPlaceOn(BlockGetter level, BlockPos pos, BlockState state) {
return state.is(ModBlocks.PRIMAL_FLESH.get()) || state.is(ModBlocks.MALIGNANT_FLESH.get());
}

@Override
public boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
Direction direction = state.getValue(FACING);
BlockPos blockPos = pos.relative(direction.getOpposite());

if (state.getBlock() == this) {
//world gen and placement
return level.getBlockState(blockPos).canSustainPlant(level, blockPos, direction, this);
}

return mayPlaceOn(level, blockPos, level.getBlockState(blockPos));
}

@Override
public boolean propagatesSkylightDown(BlockState state, BlockGetter level, BlockPos pos) {
return state.getFluidState().isEmpty();
}

@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return MalignantBloomShapes.getBoundingShape(state);
}

@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return hasCollision ? MalignantBloomShapes.getCollisionShape(state) : Shapes.empty();
}

@Override
public boolean isCollisionShapeFullBlock(BlockState state, BlockGetter level, BlockPos pos) {
return false;
}

}

0 comments on commit 6d575d2

Please sign in to comment.