diff --git a/README.md b/README.md index 473af30..a78abb8 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,18 @@ # Magisterium -Construct your own spell book from the magical pages scattered around the world! +Construct your own spell book from the magical pages scattered around the world! -It's made as an entry to Modfest 1.21, although not particularly on theme, which is "Time, Technology & Throwbacks". It may not look like one to you, bit it *is* a throwback - a throwback to Modfest 1.17, when I had the idea for book centered magic mod, yet had abandoned it. +It's made as an entry to Modfest 1.21, although not particularly on theme, which is "Time, Technology & Throwbacks". It +may not look like one to you, bit it *is* a throwback - a throwback to Modfest 1.17, when I had the idea for book +centered magic mod, yet had abandoned it. -I didn't see how it all could fit together to make a fun experience, but now (= three years later), halfway through the current modfest, the idea finished cooking in my head, and I felt like working on it. So, let's cast some spells! +I didn't see how it all could fit together to make a fun experience, but now (= three years later), halfway through the +current modfest, the idea finished cooking in my head, and I felt like working on it. So, let's cast some spells! ## Overview -The mod is centered on using spell books, which double as a container for the spell pages and as an actual book you can read and use to cast the spells within. +The mod is centered on using spell books, which double as a container for the spell pages and as an actual book you can +read and use to cast the spells within. **Spell Pages** are found in the world, currently as loot in dungeons, desert and jungle temples and strongholds. @@ -18,11 +22,13 @@ They can be inserted into a spell book in the **Arcane Table**, alongside some u ![Arcane table GUI](https://github.com/reoseah/magisterium/blob/modfest-1.21/docs/img/arcane%20table%20gui%202.png?raw=true) -Then, use the spell book to read about the spell, fill ingredients and comply with the requirements, if any, and hold the chant button! +Then, use the spell book to read about the spell, fill ingredients and comply with the requirements, if any, and hold +the chant button! ![Reading a spell](https://github.com/reoseah/magisterium/blob/modfest-1.21/docs/img/illusory%20wall%20reading.png?raw=true) -A number of spells require **Arcane Glyphs** to be placed on the ground, which will define the area of effect of the spell. +A number of spells require **Arcane Glyphs** to be placed on the ground, which will define the area of effect of the +spell. Simply right click with Lapis Lazuli on the ground to place them. ![Placing glyphs](https://github.com/reoseah/magisterium/blob/modfest-1.21/docs/img/glyphs%20placement.png?raw=true) @@ -30,3 +36,18 @@ Simply right click with Lapis Lazuli on the ground to place them. Woila! You've cast a spell! ![The spell aftermath](https://github.com/reoseah/magisterium/blob/modfest-1.21/docs/img/illusory%20wall%20result.png?raw=true) + +## Playgrounds gamerule and commands + +As I want to allow players to try out the mod on ModFest showcase server, without completely breaking the adventure mode, +I've added a mini world protection system to the mod, which may be removed in the future. + +### `/gamerule enableMagisteriumPlaygrounds [true|false]` + +This gamerule, when set to true, disables the spell effects in the world, so survival/adventure players can't grief the +world with them. + +### `/magisterium playgrounds [list|get|set|remove] <...>` + +Use these commands to manage the playgrounds, which are areas where the spell effects are enabled when the gamerule is +set to true. \ No newline at end of file diff --git a/src/main/java/io/github/reoseah/magisterium/Magisterium.java b/src/main/java/io/github/reoseah/magisterium/Magisterium.java index b5347fd..74777a8 100644 --- a/src/main/java/io/github/reoseah/magisterium/Magisterium.java +++ b/src/main/java/io/github/reoseah/magisterium/Magisterium.java @@ -51,14 +51,12 @@ public class Magisterium implements ModInitializer { public static final Logger LOGGER = LoggerFactory.getLogger(Magisterium.class); - @Override public void onInitialize() { Registry.register(Registries.BLOCK, "magisterium:arcane_table", ArcaneTableBlock.INSTANCE); Registry.register(Registries.BLOCK, "magisterium:glyph", GlyphBlock.INSTANCE); Registry.register(Registries.BLOCK, "magisterium:illusory_wall", IllusoryWallBlock.INSTANCE); - - Registry.register(Registries.BLOCK, "magisterium:test", TestBlock.INSTANCE); + Registry.register(Registries.BLOCK, "magisterium:arcane_lift", ArcaneLiftBlock.INSTANCE); Registry.register(Registries.BLOCK_ENTITY_TYPE, "magisterium:illusory_wall", IllusoryWallBlockEntity.TYPE); @@ -71,6 +69,8 @@ public void onInitialize() { Registry.register(Registries.ITEM, "magisterium:illusory_wall_page", SpellPageItem.ILLUSORY_WALL); Registry.register(Registries.ITEM, "magisterium:unstable_charge_page", SpellPageItem.UNSTABLE_CHARGE); Registry.register(Registries.ITEM, "magisterium:cold_snap_page", SpellPageItem.COLD_SNAP); + Registry.register(Registries.ITEM, "magisterium:arcane_lift_page", SpellPageItem.ARCANE_LIFT); + Registry.register(Registries.ITEM, "magisterium:dispel_magic_page", SpellPageItem.DISPEL_MAGIC); Registry.register(Registries.ITEM, "magisterium:bookmark", BookmarkItem.INSTANCE); Registry.register(Registries.DATA_COMPONENT_TYPE, "magisterium:current_page", SpellBookItem.CURRENT_PAGE); @@ -91,6 +91,8 @@ public void onInitialize() { entries.add(SpellPageItem.ILLUSORY_WALL); // entries.add(SpellPageItem.UNSTABLE_CHARGE); entries.add(SpellPageItem.COLD_SNAP); + entries.add(SpellPageItem.ARCANE_LIFT); + entries.add(SpellPageItem.DISPEL_MAGIC); entries.add(BookmarkItem.INSTANCE); }) // .build(); @@ -109,6 +111,8 @@ public void onInitialize() { Registry.register(Registries.RECIPE_SERIALIZER, "magisterium:illusory_wall", IllusoryWallRecipe.SERIALIZER); Registry.register(Registries.RECIPE_SERIALIZER, "magisterium:unstable_charge", UnstableChargeRecipe.SERIALIZER); Registry.register(Registries.RECIPE_SERIALIZER, "magisterium:cold_snap", ColdSnapRecipe.SERIALIZER); + Registry.register(Registries.RECIPE_SERIALIZER, "magisterium:arcane_lift", ArcaneLiftRecipe.SERIALIZER); + Registry.register(Registries.RECIPE_SERIALIZER, "magisterium:dispel_magic", DispelMagicRecipe.SERIALIZER); Registry.register(Registries.SCREEN_HANDLER, "magisterium:spell_book", SpellBookScreenHandler.TYPE); Registry.register(Registries.SCREEN_HANDLER, "magisterium:arcane_table", ArcaneTableScreenHandler.TYPE); @@ -117,6 +121,8 @@ public void onInitialize() { Registry.register(Registries.PARTICLE_TYPE, "magisterium:glyph_a", MagisteriumParticles.GLYPH_A); Registry.register(Registries.PARTICLE_TYPE, "magisterium:glyph_b", MagisteriumParticles.GLYPH_B); Registry.register(Registries.PARTICLE_TYPE, "magisterium:glyph_c", MagisteriumParticles.GLYPH_C); + Registry.register(Registries.PARTICLE_TYPE, "magisterium:glyph_d", MagisteriumParticles.GLYPH_D); + Registry.register(Registries.PARTICLE_TYPE, "magisterium:glyph_e", MagisteriumParticles.GLYPH_E); MagisteriumGameRules.initialize(); MagisteriumCommands.initialize(); @@ -145,8 +151,8 @@ public void onInitialize() { } }); ServerPlayNetworking.registerGlobalReceiver(UseBookmarkPayload.ID, (payload, context) -> { - if (context.player().currentScreenHandler instanceof SpellBookScreenHandler hemonomiconScreen) { - hemonomiconScreen.currentPage.set(payload.page()); + if (context.player().currentScreenHandler instanceof SpellBookScreenHandler handler) { + handler.currentPage.set(payload.page()); } }); } diff --git a/src/main/java/io/github/reoseah/magisterium/MagisteriumClient.java b/src/main/java/io/github/reoseah/magisterium/MagisteriumClient.java index 90f3a32..d278dd5 100644 --- a/src/main/java/io/github/reoseah/magisterium/MagisteriumClient.java +++ b/src/main/java/io/github/reoseah/magisterium/MagisteriumClient.java @@ -49,5 +49,7 @@ public void onInitializeClient() { ParticleFactoryRegistry.getInstance().register(MagisteriumParticles.GLYPH_A, GlyphParticle.Factory::new); ParticleFactoryRegistry.getInstance().register(MagisteriumParticles.GLYPH_B, GlyphParticle.Factory::new); ParticleFactoryRegistry.getInstance().register(MagisteriumParticles.GLYPH_C, GlyphParticle.Factory::new); + ParticleFactoryRegistry.getInstance().register(MagisteriumParticles.GLYPH_D, GlyphParticle.Factory::new); + ParticleFactoryRegistry.getInstance().register(MagisteriumParticles.GLYPH_E, GlyphParticle.Factory::new); } } \ No newline at end of file diff --git a/src/main/java/io/github/reoseah/magisterium/block/ArcaneLiftBlock.java b/src/main/java/io/github/reoseah/magisterium/block/ArcaneLiftBlock.java new file mode 100644 index 0000000..86fdd03 --- /dev/null +++ b/src/main/java/io/github/reoseah/magisterium/block/ArcaneLiftBlock.java @@ -0,0 +1,176 @@ +package io.github.reoseah.magisterium.block; + +import io.github.reoseah.magisterium.particle.MagisteriumParticles; +import net.minecraft.block.*; +import net.minecraft.block.piston.PistonBehavior; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.state.StateManager; +import net.minecraft.state.property.BooleanProperty; +import net.minecraft.state.property.IntProperty; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.random.Random; +import net.minecraft.util.shape.VoxelShape; +import net.minecraft.util.shape.VoxelShapes; +import net.minecraft.world.BlockView; +import net.minecraft.world.World; +import net.minecraft.world.WorldAccess; + +public class ArcaneLiftBlock extends Block implements Dispelable { + // public static final BooleanProperty BASE = BooleanProperty.of("base"); + public static final IntProperty HEIGHT = IntProperty.of("height", 0, 15); + + public static final Block INSTANCE = new ArcaneLiftBlock(Settings.create() // + .resistance(6000000.0F) // + .replaceable() // + .breakInstantly() // + .noBlockBreakParticles() // + .nonOpaque() // + .noCollision() // + .pistonBehavior(PistonBehavior.DESTROY)// + .luminance(state -> state.get(HEIGHT) == 0 ? 13 : 8) // + ); + + public ArcaneLiftBlock(Settings settings) { + super(settings); + this.setDefaultState(this.getStateManager().getDefaultState().with(HEIGHT, 0)); + } + + @Override + protected void appendProperties(StateManager.Builder builder) { + super.appendProperties(builder); + builder.add(HEIGHT); + } + + @Override + protected BlockRenderType getRenderType(BlockState state) { + return BlockRenderType.INVISIBLE; + } + + @Override + protected VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { + return VoxelShapes.empty(); + } + + @Override + public void randomDisplayTick(BlockState state, World world, BlockPos pos, Random random) { + + if (random.nextInt(4) == 0) { + double x = pos.getX() - .5 + random.nextFloat() * 2; + double y = pos.getY() - .5 + random.nextFloat() * 2; + double z = pos.getZ() - .5 + random.nextFloat() * 2; + var particle = MagisteriumParticles.GLYPHS[random.nextInt(MagisteriumParticles.GLYPHS.length)]; + world.addParticle(particle, x, y, z, 0, 0, 0); + } + boolean isBase = state.get(HEIGHT) == 0; + for (int i = 0; i < (isBase ? 3 : 6); i++) { + double x = pos.getX() - .5 + random.nextFloat() + random.nextFloat(); + double y = pos.getY() - .5 + random.nextFloat() + random.nextFloat(); + double z = pos.getZ() - .5 + random.nextFloat() + random.nextFloat(); + world.addParticle(MagisteriumParticles.ENERGY, x, y, z, // + 0.01 * random.nextFloat(), 0.05, 0.01 * random.nextFloat()); + } + if (isBase) { + for (int i = 0; i < 6; i++) { + double y = pos.getY() + random.nextFloat() * .5; + double x, z; + if (random.nextBoolean()) { + x = pos.getX() + (random.nextBoolean() ? -.5 : 1.5); + z = pos.getZ() - .5 + 2 * random.nextFloat(); + } else { + z = pos.getZ() + (random.nextBoolean() ? -.5 : 1.5); + x = pos.getX() - .5 + 2 * random.nextFloat(); + } + double centerX = pos.getX() + .5; + double centerZ = pos.getZ() + .5; + double velocityX = (centerX - x) * 0.03; + double velocityZ = (centerZ - z) * 0.03; + world.addParticle(MagisteriumParticles.ENERGY, // + x - .25 + random.nextFloat() * .5, y, z - .25 + random.nextFloat() * .5, // + velocityX, 0.05, velocityZ); + } + } + } + + @Override + protected void onEntityCollision(BlockState state, World world, BlockPos pos, Entity entity) { + var velocity = entity.getVelocity(); + if (entity.isDescending()) { + double velocityY = Math.max(velocity.y, -0.1); + entity.setVelocity(velocity.x, velocityY, velocity.z); + } else { + double velocityY = MathHelper.clamp(velocity.y + 0.03, 0.25, 0.75); + entity.setVelocity(velocity.x, velocityY, velocity.z); + } + entity.limitFallDistance(); + } + + @Override + protected BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState neighborState, WorldAccess world, BlockPos pos, BlockPos neighborPos) { + world.scheduleBlockTick(pos, this, 5); + return state; + } + + @Override + protected void onBlockAdded(BlockState state, World world, BlockPos pos, BlockState oldState, boolean notify) { + super.onBlockAdded(state, world, pos, oldState, notify); + world.scheduleBlockTick(pos, this, 5); + } + + @Override + protected void scheduledTick(BlockState state, ServerWorld world, BlockPos pos, Random random) { + if (state.get(HEIGHT) == 0) { + for (int dx = -1; dx <= 1; dx++) { + for (int dz = -1; dz <= 1; dz++) { + if (dx == 0 && dz == 0) { + continue; + } + var neighborPos = pos.add(dx, 0, dz); + var neighborState = world.getBlockState(neighborPos); + if (neighborState.getBlock() != GlyphBlock.INSTANCE) { + world.removeBlock(pos, false); + return; + } + } + } + } else { + var below = pos.down(); + var stateBelow = world.getBlockState(below); + if (stateBelow.getBlock() != this) { + world.removeBlock(pos, false); + return; + } + } + + if (state.get(HEIGHT) < 15) { + var above = pos.up(); + if (world.isAir(above)) { + world.setBlockState(above, state.with(HEIGHT, state.get(HEIGHT) + 1)); + } + } + } + + @Override + public void dispel(World world, BlockPos pos, PlayerEntity player) { + var state = world.getBlockState(pos); + var height = state.get(HEIGHT); + for (var ipos : BlockPos.iterate(pos, pos.add(0, -height, 0))) { + if (world.getBlockState(ipos).getBlock() != this) { + break; + } + world.setBlockState(ipos, Blocks.AIR.getDefaultState(), 3); + world.syncWorldEvent(null, 2001, ipos, Block.getRawIdFromState(state)); + } + for (var ipos : BlockPos.iterate(pos, pos.add(0, 15 - height, 0))) { + if (world.getBlockState(ipos).getBlock() != GlyphBlock.INSTANCE) { + break; + } + world.setBlockState(ipos, Blocks.AIR.getDefaultState(), 3); + world.syncWorldEvent(null, 2001, ipos, Block.getRawIdFromState(state)); + } + } +} diff --git a/src/main/java/io/github/reoseah/magisterium/block/Dispelable.java b/src/main/java/io/github/reoseah/magisterium/block/Dispelable.java new file mode 100644 index 0000000..b58f237 --- /dev/null +++ b/src/main/java/io/github/reoseah/magisterium/block/Dispelable.java @@ -0,0 +1,9 @@ +package io.github.reoseah.magisterium.block; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public interface Dispelable { + void dispel(World world, BlockPos pos, PlayerEntity player); +} diff --git a/src/main/java/io/github/reoseah/magisterium/block/IllusoryWallBlock.java b/src/main/java/io/github/reoseah/magisterium/block/IllusoryWallBlock.java index 2ad625c..64fb691 100644 --- a/src/main/java/io/github/reoseah/magisterium/block/IllusoryWallBlock.java +++ b/src/main/java/io/github/reoseah/magisterium/block/IllusoryWallBlock.java @@ -17,7 +17,7 @@ import java.util.ArrayDeque; import java.util.HashSet; -public class IllusoryWallBlock extends BlockWithEntity { +public class IllusoryWallBlock extends BlockWithEntity implements Dispelable { public static final MapCodec CODEC = createCodec(IllusoryWallBlock::new); public static final Settings SETTINGS = Settings.create().nonOpaque().noCollision().strength(0.5F); public static final Block INSTANCE = new IllusoryWallBlock(SETTINGS); @@ -81,4 +81,9 @@ public void onBroken(WorldAccess world, BlockPos pos, BlockState state) { } } } + + @Override + public void dispel(World world, BlockPos pos, PlayerEntity player) { + MagisteriumPlaygrounds.trySetBlockState(world, pos, Blocks.AIR.getDefaultState(), player); + } } diff --git a/src/main/java/io/github/reoseah/magisterium/block/MagisteriumBlockTags.java b/src/main/java/io/github/reoseah/magisterium/block/MagisteriumBlockTags.java index 5f5f235..d5b13a5 100644 --- a/src/main/java/io/github/reoseah/magisterium/block/MagisteriumBlockTags.java +++ b/src/main/java/io/github/reoseah/magisterium/block/MagisteriumBlockTags.java @@ -7,4 +7,5 @@ public class MagisteriumBlockTags { public static final TagKey AWAKEN_THE_FIRE_TARGETS = TagKey.of(RegistryKeys.BLOCK, Identifier.of("magisterium:awaken_the_fire_targets")); + public static final TagKey DISPEL_MAGIC_SUSCEPTIBLE = TagKey.of(RegistryKeys.BLOCK, Identifier.of("magisterium:dispel_magic_susceptible")); } diff --git a/src/main/java/io/github/reoseah/magisterium/block/TestBlock.java b/src/main/java/io/github/reoseah/magisterium/block/TestBlock.java deleted file mode 100644 index 886373f..0000000 --- a/src/main/java/io/github/reoseah/magisterium/block/TestBlock.java +++ /dev/null @@ -1,49 +0,0 @@ -package io.github.reoseah.magisterium.block; - -import io.github.reoseah.magisterium.particle.MagisteriumParticles; -import net.minecraft.block.Block; -import net.minecraft.block.BlockRenderType; -import net.minecraft.block.BlockState; -import net.minecraft.particle.ParticleTypes; -import net.minecraft.particle.SimpleParticleType; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.random.Random; -import net.minecraft.world.World; - -public class TestBlock extends Block { - public static final Block INSTANCE = new TestBlock(Settings.create().nonOpaque().noCollision()); - - public TestBlock(Settings settings) { - super(settings); - } - - @Override - protected BlockRenderType getRenderType(BlockState state) { - return BlockRenderType.INVISIBLE; - } - - @Override - public void randomDisplayTick(BlockState state, World world, BlockPos pos, Random random) { - super.randomDisplayTick(state, world, pos, random); - - var types = new SimpleParticleType[]{ // - MagisteriumParticles.GLYPH_A, // - MagisteriumParticles.GLYPH_B, // - MagisteriumParticles.GLYPH_C // - }; - - for (int i = 0; i < 1; i++) { - double x = pos.getX() + .5 + random.nextGaussian(); - double y = pos.getY() + .5 + random.nextGaussian(); - double z = pos.getZ() + .5 + random.nextGaussian(); - world.addParticle(types[random.nextInt(types.length)], x, y, z, 0.0D, 0.0D, 0.0D); - } - - for (int i = 0; i < 4; i++) { - double x = pos.getX() + .5 + random.nextGaussian(); - double y = pos.getY() + .5 + random.nextGaussian(); - double z = pos.getZ() + .5 + random.nextGaussian(); - world.addParticle(MagisteriumParticles.ENERGY, x, y, z, 0.0D, 0.05D, 0.0D); - } - } -} diff --git a/src/main/java/io/github/reoseah/magisterium/item/SpellBookItem.java b/src/main/java/io/github/reoseah/magisterium/item/SpellBookItem.java index 67ad951..af66ee9 100644 --- a/src/main/java/io/github/reoseah/magisterium/item/SpellBookItem.java +++ b/src/main/java/io/github/reoseah/magisterium/item/SpellBookItem.java @@ -55,7 +55,9 @@ public static ItemStack createTestBook() { list.set(4, SpellPageItem.CONFLAGRATE.getDefaultStack()); list.set(5, SpellPageItem.ILLUSORY_WALL.getDefaultStack()); // list.set(6, SpellPageItem.UNSTABLE_CHARGE.getDefaultStack()); + list.set(6, SpellPageItem.ARCANE_LIFT.getDefaultStack()); list.set(7, SpellPageItem.COLD_SNAP.getDefaultStack()); + list.set(8, SpellPageItem.DISPEL_MAGIC.getDefaultStack()); })); return book; diff --git a/src/main/java/io/github/reoseah/magisterium/item/SpellPageItem.java b/src/main/java/io/github/reoseah/magisterium/item/SpellPageItem.java index 4a58e88..e0b5408 100644 --- a/src/main/java/io/github/reoseah/magisterium/item/SpellPageItem.java +++ b/src/main/java/io/github/reoseah/magisterium/item/SpellPageItem.java @@ -17,6 +17,8 @@ public class SpellPageItem extends Item { public static final Item ILLUSORY_WALL = new SpellPageItem(new Item.Settings().maxCount(16), Identifier.of("magisterium:illusory_wall")); public static final Item UNSTABLE_CHARGE = new SpellPageItem(new Item.Settings().maxCount(16), Identifier.of("magisterium:unstable_charge")); public static final Item COLD_SNAP = new SpellPageItem(new Item.Settings().maxCount(16), Identifier.of("magisterium:cold_snap")); + public static final Item ARCANE_LIFT = new SpellPageItem(new Item.Settings().maxCount(16), Identifier.of("magisterium:arcane_lift")); + public static final Item DISPEL_MAGIC = new SpellPageItem(new Item.Settings().maxCount(16), Identifier.of("magisterium:dispel_magic")); public final Identifier spell; protected final Text tooltip; diff --git a/src/main/java/io/github/reoseah/magisterium/particle/EnergyParticle.java b/src/main/java/io/github/reoseah/magisterium/particle/EnergyParticle.java index c23f6fb..902f2ea 100644 --- a/src/main/java/io/github/reoseah/magisterium/particle/EnergyParticle.java +++ b/src/main/java/io/github/reoseah/magisterium/particle/EnergyParticle.java @@ -11,7 +11,7 @@ protected EnergyParticle(ClientWorld clientWorld, double x, double y, double z, super(clientWorld, x, y, z, velocityX, velocityY, velocityZ); this.maxAge = 8 + this.random.nextInt(24); this.setSprite(spriteProvider); - float brightness = this.random.nextFloat() * 0.6F + 0.4F; + float brightness = this.random.nextFloat() * 0.7F + 0.3F; this.red = brightness * 0.1F; this.green = brightness * 0.5F; this.blue = brightness; @@ -42,9 +42,9 @@ public void tick() { return; } this.move(this.velocityX, this.velocityY, this.velocityZ); - this.velocityX *= 0.99D; - this.velocityY *= 0.99D; - this.velocityZ *= 0.99D; + this.velocityX *= 0.98; + this.velocityY *= 0.98; + this.velocityZ *= 0.98; } @Environment(EnvType.CLIENT) diff --git a/src/main/java/io/github/reoseah/magisterium/particle/GlyphParticle.java b/src/main/java/io/github/reoseah/magisterium/particle/GlyphParticle.java index c88ee9a..60c745d 100644 --- a/src/main/java/io/github/reoseah/magisterium/particle/GlyphParticle.java +++ b/src/main/java/io/github/reoseah/magisterium/particle/GlyphParticle.java @@ -13,7 +13,7 @@ public class GlyphParticle extends SpriteBillboardParticle { public GlyphParticle(ClientWorld clientWorld, double x, double y, double z, double velocityX, double velocityY, double velocityZ, SpriteProvider spriteProvider) { super(clientWorld, x, y, z, velocityX, velocityY, velocityZ); this.spriteProvider = spriteProvider; - this.maxAge = 16; + this.maxAge = 32; this.setSpriteForAge(spriteProvider); this.scale = .5F; diff --git a/src/main/java/io/github/reoseah/magisterium/particle/MagisteriumParticles.java b/src/main/java/io/github/reoseah/magisterium/particle/MagisteriumParticles.java index da78b62..cb61e01 100644 --- a/src/main/java/io/github/reoseah/magisterium/particle/MagisteriumParticles.java +++ b/src/main/java/io/github/reoseah/magisterium/particle/MagisteriumParticles.java @@ -7,6 +7,10 @@ public class MagisteriumParticles { public static final SimpleParticleType GLYPH_A = new MagisteriumParticleType(true); public static final SimpleParticleType GLYPH_B = new MagisteriumParticleType(true); public static final SimpleParticleType GLYPH_C = new MagisteriumParticleType(true); + public static final SimpleParticleType GLYPH_D = new MagisteriumParticleType(true); + public static final SimpleParticleType GLYPH_E = new MagisteriumParticleType(true); + + public static final SimpleParticleType[] GLYPHS = {GLYPH_A, GLYPH_B, GLYPH_C, GLYPH_D, GLYPH_E}; // makes constructor public public static class MagisteriumParticleType extends SimpleParticleType { diff --git a/src/main/java/io/github/reoseah/magisterium/recipe/ArcaneLiftRecipe.java b/src/main/java/io/github/reoseah/magisterium/recipe/ArcaneLiftRecipe.java new file mode 100644 index 0000000..85dd60c --- /dev/null +++ b/src/main/java/io/github/reoseah/magisterium/recipe/ArcaneLiftRecipe.java @@ -0,0 +1,81 @@ +package io.github.reoseah.magisterium.recipe; + +import io.github.reoseah.magisterium.block.ArcaneLiftBlock; +import io.github.reoseah.magisterium.block.GlyphBlock; +import io.github.reoseah.magisterium.world.MagisteriumPlaygrounds; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.recipe.RecipeSerializer; +import net.minecraft.registry.RegistryWrapper; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.WorldAccess; + +public class ArcaneLiftRecipe extends SpellBookRecipe { + public static final RecipeSerializer SERIALIZER = new SpellBookRecipe.SimpleSerializer<>(ArcaneLiftRecipe::new); + + protected ArcaneLiftRecipe(Identifier utterance, int duration) { + super(utterance, duration); + } + + @Override + public boolean matches(SpellBookRecipeInput input, World world) { + return true; + } + + @Override + public ItemStack craft(SpellBookRecipeInput input, RegistryWrapper.WrapperLookup lookup) { + var world = input.getPlayer().getWorld(); + var pos = input.getPlayer().getBlockPos(); + + var circlePos = find3x3GlyphCircle(world, pos); + if (circlePos == null) { + return ItemStack.EMPTY; + } + + if (world.isAir(circlePos)) { +// world.setBlockState(circlePos, ArcaneLiftBlock.INSTANCE.getDefaultState()); + + MagisteriumPlaygrounds.trySetBlockState(world, circlePos, ArcaneLiftBlock.INSTANCE.getDefaultState(), input.getPlayer()); + // TODO check result and send feedback + } + + return ItemStack.EMPTY; + } + + private static final int SEARCH_RADIUS = 8; + + private static BlockPos find3x3GlyphCircle(WorldAccess world, BlockPos start) { + for (var pos : BlockPos.iterateOutwards(start, SEARCH_RADIUS, SEARCH_RADIUS, SEARCH_RADIUS)) { + boolean isCircle = true; + for (int dx = -1; dx <= 1; dx++) { + for (int dz = -1; dz <= 1; dz++) { + if (dx == 0 && dz == 0) { + continue; + } + if (!world.getBlockState(pos.add(dx, 0, dz)).isOf(GlyphBlock.INSTANCE)) { + isCircle = false; + continue; + } + } + } + if (isCircle) { + return pos; + } + } + + return null; + } + + @Override + public ItemStack getResult(RegistryWrapper.WrapperLookup registriesLookup) { + return ItemStack.EMPTY; + } + + @Override + public RecipeSerializer getSerializer() { + return SERIALIZER; + } +} diff --git a/src/main/java/io/github/reoseah/magisterium/recipe/DispelMagicRecipe.java b/src/main/java/io/github/reoseah/magisterium/recipe/DispelMagicRecipe.java new file mode 100644 index 0000000..0b4fca5 --- /dev/null +++ b/src/main/java/io/github/reoseah/magisterium/recipe/DispelMagicRecipe.java @@ -0,0 +1,58 @@ +package io.github.reoseah.magisterium.recipe; + +import io.github.reoseah.magisterium.block.Dispelable; +import io.github.reoseah.magisterium.block.MagisteriumBlockTags; +import io.github.reoseah.magisterium.world.MagisteriumPlaygrounds; +import net.minecraft.block.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.recipe.RecipeSerializer; +import net.minecraft.registry.RegistryWrapper; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class DispelMagicRecipe extends SpellBookRecipe { + public static final RecipeSerializer SERIALIZER = new SpellBookRecipe.SimpleSerializer<>(DispelMagicRecipe::new); + + protected DispelMagicRecipe(Identifier utterance, int duration) { + super(utterance, duration); + } + + @Override + public boolean matches(SpellBookRecipeInput input, World world) { + return true; + } + + private static final int RANGE = 16; + + @Override + public ItemStack craft(SpellBookRecipeInput input, RegistryWrapper.WrapperLookup lookup) { + var world = input.getPlayer().getWorld(); + var center = input.getPlayer().getBlockPos(); + + for (var pos : BlockPos.iterateOutwards(center, RANGE, RANGE, RANGE)) { + var state = world.getBlockState(pos); + if (state.isIn(MagisteriumBlockTags.DISPEL_MAGIC_SUSCEPTIBLE)) { + if (state.getBlock() instanceof Dispelable dispelable) { + dispelable.dispel(world, pos, input.getPlayer()); + } else { +// world.breakBlock(pos, true); + MagisteriumPlaygrounds.trySetBlockState(world, pos, Blocks.AIR.getDefaultState(), input.getPlayer()); + } + // TODO check result and send feedback + break; + } + } + return ItemStack.EMPTY; + } + + @Override + public ItemStack getResult(RegistryWrapper.WrapperLookup registriesLookup) { + return ItemStack.EMPTY; + } + + @Override + public RecipeSerializer getSerializer() { + return SERIALIZER; + } +} diff --git a/src/main/resources/assets/magisterium/blockstates/arcane_lift.json b/src/main/resources/assets/magisterium/blockstates/arcane_lift.json new file mode 100644 index 0000000..2c8f02f --- /dev/null +++ b/src/main/resources/assets/magisterium/blockstates/arcane_lift.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "minecraft:block/air" + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/magisterium/lang/en_us.json b/src/main/resources/assets/magisterium/lang/en_us.json index da30b88..daa82ff 100644 --- a/src/main/resources/assets/magisterium/lang/en_us.json +++ b/src/main/resources/assets/magisterium/lang/en_us.json @@ -2,15 +2,17 @@ "itemGroup.magisterium": "Magisterium", "block.magisterium.arcane_table": "Arcane Table", "block.magisterium.glyph": "Arcane Glyph", + "block.magisterium.illusory_wall": "Illusory Wall", + "block.magisterium.arcane_lift": "Arcane Lift", "item.magisterium.spell_book": "Spell Tome", "item.magisterium.spell_book.unstable_charge": "Unstable Charge", "item.magisterium.spell_book.empty": "Empty", "item.magisterium.spell_book.pages": "%s Entries", "item.magisterium.spell_page": "Spell Page", "item.magisterium.bookmark": "Silk Bookmark", - "tags.item.magisterium.spell_pages": "Spell Pages", - "tags.item.magisterium.spell_book_components": "Spell Book Components", - "tags.item.magisterium.conflagrate_ingredients": "Conflagrate Ingredients", + "tag.item.magisterium.spell_pages": "Spell Pages", + "tag.item.magisterium.spell_book_components": "Spell Book Components", + "tag.item.magisterium.conflagrate_ingredients": "Conflagrate Ingredients", "container.magisterium.arcane_table": "Arcane Table", "gamerule.enableMagisteriumPlaygrounds": "Enable Magisterium playgrounds (block most spells outside the designated areas, see /magisterium playgrounds)", "commands.magisterium.playgrounds.list.success": "Available playgrounds: %s", @@ -58,6 +60,16 @@ "magisterium.spell.magisterium.illusory_wall.components": "ᴄᴏᴍᴘᴏɴᴇɴᴛs: material that the wall is to be made of, a line of arcane glyphs on the ground", "magisterium.spell.magisterium.illusory_wall.description": "Create a wall of illusion that seems solid, but can be passed through.", "magisterium.spell.magisterium.illusory_wall.utterance": "Pᴀʀɪᴇs ꜰᴀʟʟᴀx, ᴠɪᴅᴇᴀʀɪs ꜰɪʀᴍᴜs ᴇᴛ ᴀʟᴛᴜs!\n\nTᴀɴɢᴀɴᴛ ᴛᴇ ꜰʀᴜsᴛʀᴀ, sᴏʟɪᴅᴜᴍ ᴠɪᴅᴇʀᴇ sᴇᴅ ᴜᴍʙʀᴀ sɪs.\n\nVᴇʀɪᴛᴀs ᴀʙsᴄᴏɴᴅɪᴛᴀ, ᴜᴍʙʀᴀ ᴘᴇʀᴍᴀɴᴇ!", + "magisterium.spell.magisterium.arcane_lift": "Arcane Lift", + "magisterium.spell.magisterium.arcane_lift.heading": "ᴀʀᴄᴀɴᴇ ʟɪꜰᴛ", + "magisterium.spell.magisterium.arcane_lift.components": "ᴄᴏᴍᴘᴏɴᴇɴᴛs: a three by three circle of arcane glyphs, TODO something", + "magisterium.spell.magisterium.arcane_lift.description": "Call into existence a rising stream of arcane energy that lifts the creatures and objects into the air.", + "magisterium.spell.magisterium.arcane_lift.utterance": "TODO TODO TODO\n\nTODO TODO TODO\n\nTODO TODO TODO", + "magisterium.spell.magisterium.dispel_magic": "Dispel Magic", + "magisterium.spell.magisterium.dispel_magic.heading": "ᴅɪsᴘᴇʟ ᴍᴀɢɪᴄ", + "magisterium.spell.magisterium.dispel_magic.components": "ᴄᴏᴍᴘᴏɴᴇɴᴛs: TODO", + "magisterium.spell.magisterium.dispel_magic.description": "End the effects of the closest spell or magical effect.", + "magisterium.spell.magisterium.dispel_magic.utterance": "TODO TODO TODO\n\nTODO TODO TODO\n\nTODO TODO TODO", "magisterium.spell.magisterium.unstable_charge": "Unstable Charge", "magisterium.spell.magisterium.unstable_charge.heading": "ᴜɴsᴛᴀʙʟᴇ ᴄʜᴀʀɢᴇ", "magisterium.spell.magisterium.unstable_charge.components": "ᴄᴏᴍᴘᴏɴᴇɴᴛs: one measure of nether wart and a bottle of liquid magic", diff --git a/src/main/resources/assets/magisterium/lang/ru_ru.json b/src/main/resources/assets/magisterium/lang/ru_ru.json index 7fb45ff..f8cfd6b 100644 --- a/src/main/resources/assets/magisterium/lang/ru_ru.json +++ b/src/main/resources/assets/magisterium/lang/ru_ru.json @@ -5,8 +5,9 @@ "item.magisterium.spell_book": "Книга заклинаний", "item.magisterium.spell_page": "Страница заклинания", "item.magisterium.bookmark": "Шелковая закладка", - "tags.item.magisterium.spell_book_components": "Части книги заклинаний", - "tags.item.magisterium.conflagrate_ingredients": "Ингредиенты для заклинания конфлаграция", + "tag.item.magisterium.spell_pages": "Страницы заклинаний", + "tag.item.magisterium.spell_book_components": "Части книги заклинаний", + "tag.item.magisterium.conflagrate_ingredients": "Ингредиенты для заклинания конфлаграция", "container.magisterium.arcane_table": "Мистический стол", "magisterium.gui.untitled_section": "Без названия", "magisterium.gui.untitled_section.description": "Переименуйте закладкy, чтобы дать разделу название.", diff --git a/src/main/resources/assets/magisterium/magisterium/spells/arcane_lift.json b/src/main/resources/assets/magisterium/magisterium/spells/arcane_lift.json new file mode 100644 index 0000000..b0b1384 --- /dev/null +++ b/src/main/resources/assets/magisterium/magisterium/spells/arcane_lift.json @@ -0,0 +1,43 @@ +{ + "elements": [ + { + "type": "fold", + "left": [ + { + "type": "heading", + "translation_key": "magisterium.spell.magisterium.arcane_lift.heading" + }, + { + "type": "paragraph", + "translation_key": "magisterium.spell.magisterium.arcane_lift.components" + }, + { + "type": "paragraph", + "translation_key": "magisterium.spell.magisterium.arcane_lift.description" + } + ], + "right": [ + { + "type": "heading", + "translation_key": "magisterium.spell.magisterium.arcane_lift.heading" + }, + { + "type": "inventory", + "slots": [ + { + "x": 42, + "y": 0, + "background": "magisterium:item/placeholder/question_mark" + } + ] + }, + { + "type": "utterance", + "id": "magisterium:arcane_lift", + "translation_key": "magisterium.spell.magisterium.arcane_lift.utterance", + "duration": 8 + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/magisterium/magisterium/spells/dispel_magic.json b/src/main/resources/assets/magisterium/magisterium/spells/dispel_magic.json new file mode 100644 index 0000000..b92c5a4 --- /dev/null +++ b/src/main/resources/assets/magisterium/magisterium/spells/dispel_magic.json @@ -0,0 +1,21 @@ +{ + "elements": [ + { + "type": "heading", + "translation_key": "magisterium.spell.magisterium.dispel_magic.heading" + }, + { + "type": "paragraph", + "translation_key": "magisterium.spell.magisterium.dispel_magic.description" + }, + { + "type": "utterance", + "id": "magisterium:dispel_magic", + "translation_key": "magisterium.spell.magisterium.dispel_magic.utterance", + "duration": 4 + }, + { + "type": "page_break" + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/magisterium/models/item/arcane_lift_page.json b/src/main/resources/assets/magisterium/models/item/arcane_lift_page.json new file mode 100644 index 0000000..c802402 --- /dev/null +++ b/src/main/resources/assets/magisterium/models/item/arcane_lift_page.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "magisterium:item/arcane_lift_page" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/magisterium/models/item/dispel_magic_page.json b/src/main/resources/assets/magisterium/models/item/dispel_magic_page.json new file mode 100644 index 0000000..af58ff8 --- /dev/null +++ b/src/main/resources/assets/magisterium/models/item/dispel_magic_page.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "magisterium:item/dispel_magic_page" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/magisterium/particles/glyph_d.json b/src/main/resources/assets/magisterium/particles/glyph_d.json new file mode 100644 index 0000000..9978039 --- /dev/null +++ b/src/main/resources/assets/magisterium/particles/glyph_d.json @@ -0,0 +1,12 @@ +{ + "textures": [ + "magisterium:glyph_d_3", + "magisterium:glyph_d_3", + "magisterium:glyph_d_3", + "magisterium:glyph_d_3", + "magisterium:glyph_d_2", + "magisterium:glyph_d_2", + "magisterium:glyph_d_1", + "magisterium:glyph_d_0" + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/magisterium/particles/glyph_e.json b/src/main/resources/assets/magisterium/particles/glyph_e.json new file mode 100644 index 0000000..4ec8503 --- /dev/null +++ b/src/main/resources/assets/magisterium/particles/glyph_e.json @@ -0,0 +1,12 @@ +{ + "textures": [ + "magisterium:glyph_e_3", + "magisterium:glyph_e_3", + "magisterium:glyph_e_3", + "magisterium:glyph_e_3", + "magisterium:glyph_e_2", + "magisterium:glyph_e_2", + "magisterium:glyph_e_1", + "magisterium:glyph_e_0" + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/magisterium/textures/item/arcane_lift_page.png b/src/main/resources/assets/magisterium/textures/item/arcane_lift_page.png new file mode 100644 index 0000000..f0f58fb Binary files /dev/null and b/src/main/resources/assets/magisterium/textures/item/arcane_lift_page.png differ diff --git a/src/main/resources/assets/magisterium/textures/item/dispel_magic_page.png b/src/main/resources/assets/magisterium/textures/item/dispel_magic_page.png new file mode 100644 index 0000000..34d300e Binary files /dev/null and b/src/main/resources/assets/magisterium/textures/item/dispel_magic_page.png differ diff --git a/src/main/resources/assets/magisterium/textures/particle/glyph_a_0.png b/src/main/resources/assets/magisterium/textures/particle/glyph_a_0.png index 6fce8fd..bd811c3 100644 Binary files a/src/main/resources/assets/magisterium/textures/particle/glyph_a_0.png and b/src/main/resources/assets/magisterium/textures/particle/glyph_a_0.png differ diff --git a/src/main/resources/assets/magisterium/textures/particle/glyph_a_1.png b/src/main/resources/assets/magisterium/textures/particle/glyph_a_1.png index 3357313..8082731 100644 Binary files a/src/main/resources/assets/magisterium/textures/particle/glyph_a_1.png and b/src/main/resources/assets/magisterium/textures/particle/glyph_a_1.png differ diff --git a/src/main/resources/assets/magisterium/textures/particle/glyph_d_0.png b/src/main/resources/assets/magisterium/textures/particle/glyph_d_0.png new file mode 100644 index 0000000..c879906 Binary files /dev/null and b/src/main/resources/assets/magisterium/textures/particle/glyph_d_0.png differ diff --git a/src/main/resources/assets/magisterium/textures/particle/glyph_d_1.png b/src/main/resources/assets/magisterium/textures/particle/glyph_d_1.png new file mode 100644 index 0000000..786379c Binary files /dev/null and b/src/main/resources/assets/magisterium/textures/particle/glyph_d_1.png differ diff --git a/src/main/resources/assets/magisterium/textures/particle/glyph_d_2.png b/src/main/resources/assets/magisterium/textures/particle/glyph_d_2.png new file mode 100644 index 0000000..6007e19 Binary files /dev/null and b/src/main/resources/assets/magisterium/textures/particle/glyph_d_2.png differ diff --git a/src/main/resources/assets/magisterium/textures/particle/glyph_d_3.png b/src/main/resources/assets/magisterium/textures/particle/glyph_d_3.png new file mode 100644 index 0000000..0b903d0 Binary files /dev/null and b/src/main/resources/assets/magisterium/textures/particle/glyph_d_3.png differ diff --git a/src/main/resources/assets/magisterium/textures/particle/glyph_e_0.png b/src/main/resources/assets/magisterium/textures/particle/glyph_e_0.png new file mode 100644 index 0000000..1e3a5a4 Binary files /dev/null and b/src/main/resources/assets/magisterium/textures/particle/glyph_e_0.png differ diff --git a/src/main/resources/assets/magisterium/textures/particle/glyph_e_1.png b/src/main/resources/assets/magisterium/textures/particle/glyph_e_1.png new file mode 100644 index 0000000..e3808d0 Binary files /dev/null and b/src/main/resources/assets/magisterium/textures/particle/glyph_e_1.png differ diff --git a/src/main/resources/assets/magisterium/textures/particle/glyph_e_2.png b/src/main/resources/assets/magisterium/textures/particle/glyph_e_2.png new file mode 100644 index 0000000..453fe0f Binary files /dev/null and b/src/main/resources/assets/magisterium/textures/particle/glyph_e_2.png differ diff --git a/src/main/resources/assets/magisterium/textures/particle/glyph_e_3.png b/src/main/resources/assets/magisterium/textures/particle/glyph_e_3.png new file mode 100644 index 0000000..7baa5d8 Binary files /dev/null and b/src/main/resources/assets/magisterium/textures/particle/glyph_e_3.png differ diff --git a/src/main/resources/data/magisterium/recipe/arcane_lift.json b/src/main/resources/data/magisterium/recipe/arcane_lift.json new file mode 100644 index 0000000..54cc568 --- /dev/null +++ b/src/main/resources/data/magisterium/recipe/arcane_lift.json @@ -0,0 +1,5 @@ +{ + "type": "magisterium:arcane_lift", + "utterance": "magisterium:arcane_lift", + "duration": 8 +} \ No newline at end of file diff --git a/src/main/resources/data/magisterium/recipe/dispel_magic.json b/src/main/resources/data/magisterium/recipe/dispel_magic.json new file mode 100644 index 0000000..35f18b3 --- /dev/null +++ b/src/main/resources/data/magisterium/recipe/dispel_magic.json @@ -0,0 +1,5 @@ +{ + "type": "magisterium:dispel_magic", + "utterance": "magisterium:dispel_magic", + "duration": 4 +} \ No newline at end of file diff --git a/src/main/resources/data/magisterium/tags/block/dispel_magic_susceptible.json b/src/main/resources/data/magisterium/tags/block/dispel_magic_susceptible.json new file mode 100644 index 0000000..6dc1f13 --- /dev/null +++ b/src/main/resources/data/magisterium/tags/block/dispel_magic_susceptible.json @@ -0,0 +1,6 @@ +{ + "values": [ + "magisterium:illusory_wall", + "magisterium:arcane_lift" + ] +} \ No newline at end of file diff --git a/src/main/resources/data/magisterium/tags/item/spell_pages.json b/src/main/resources/data/magisterium/tags/item/spell_pages.json index b5c35c2..baca71e 100644 --- a/src/main/resources/data/magisterium/tags/item/spell_pages.json +++ b/src/main/resources/data/magisterium/tags/item/spell_pages.json @@ -6,6 +6,8 @@ "magisterium:conflagrate_page", "magisterium:illusory_wall_page", "magisterium:unstable_charge_page", - "magisterium:cold_snap_page" + "magisterium:cold_snap_page", + "magisterium:arcane_lift_page", + "magisterium:dispel_magic_page" ] } \ No newline at end of file diff --git a/src/main/resources/data/minecraft/tags/block/mineable/axe.json b/src/main/resources/data/minecraft/tags/block/mineable/axe.json new file mode 100644 index 0000000..46b9267 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/block/mineable/axe.json @@ -0,0 +1,5 @@ +{ + "values": [ + "magisterium:arcane_table" + ] +} \ No newline at end of file