mirror of
https://github.com/Sollace/Unicopia.git
synced 2025-02-17 10:24:23 +01:00
Reimplement Fire and Ice gems
This commit is contained in:
parent
ceab6d6914
commit
96809095c2
15 changed files with 728 additions and 55 deletions
|
@ -7,6 +7,7 @@ import net.minecraft.client.Minecraft;
|
|||
import net.minecraft.client.particle.IParticleFactory;
|
||||
import net.minecraft.client.particle.Particle;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
public class Particles {
|
||||
|
||||
|
@ -32,6 +33,10 @@ public class Particles {
|
|||
return -id - 1;
|
||||
}
|
||||
|
||||
public Particle spawnParticle(int particleId, boolean ignoreDistance, Vec3d pos, double speedX, double speedY, double speedZ, int ...pars) {
|
||||
return spawnParticle(particleId, ignoreDistance, pos, speedX, speedY, speedZ, pars);
|
||||
}
|
||||
|
||||
public Particle spawnParticle(int particleId, boolean ignoreDistance, double posX, double posY, double posZ, double speedX, double speedY, double speedZ, int ...pars) {
|
||||
Entity entity = mc.getRenderViewEntity();
|
||||
|
||||
|
|
|
@ -146,6 +146,20 @@ public class ItemSpell extends Item implements ICastable {
|
|||
return new ActionResult<ItemStack>(EnumActionResult.FAIL, stack);
|
||||
}
|
||||
|
||||
IMagicEffect effect = SpellRegistry.instance().getSpellFromItemStack(stack);
|
||||
|
||||
if (effect instanceof IUseAction) {
|
||||
SpellCastResult result = ((IUseAction)effect).onUse(stack, player, world, target);
|
||||
|
||||
if (result != SpellCastResult.NONE) {
|
||||
if (result == SpellCastResult.PLACE && !player.capabilities.isCreativeMode) {
|
||||
stack.shrink(1);
|
||||
}
|
||||
|
||||
return new ActionResult<ItemStack>(EnumActionResult.SUCCESS, stack);
|
||||
}
|
||||
}
|
||||
|
||||
return new ActionResult<ItemStack>(EnumActionResult.PASS, stack);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
package com.minelittlepony.unicopia.spell;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.minelittlepony.unicopia.player.IOwned;
|
||||
import com.minelittlepony.util.shape.IShape;
|
||||
import com.minelittlepony.util.vector.VecHelper;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public interface ICaster<E extends EntityLivingBase> extends IOwned<E>, ILevelled {
|
||||
|
@ -30,4 +37,20 @@ public interface ICaster<E extends EntityLivingBase> extends IOwned<E>, ILevelle
|
|||
default BlockPos getOrigin() {
|
||||
return getEntity().getPosition();
|
||||
}
|
||||
|
||||
default void spawnParticles(IShape area, int count, Consumer<Vec3d> particleSpawner) {
|
||||
Random rand = getWorld().rand;
|
||||
|
||||
int x = getOrigin().getX();
|
||||
int y = getOrigin().getY();
|
||||
int z = getOrigin().getZ();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
particleSpawner.accept(area.computePoint(rand).add(x, y, z));
|
||||
}
|
||||
}
|
||||
|
||||
default Stream<Entity> findAllEntitiesInRange(double radius) {
|
||||
return VecHelper.findAllEntitiesInRange(getEntity(), getWorld(), getOrigin(), radius);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.minelittlepony.unicopia.spell;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
@ -12,10 +14,10 @@ import net.minecraft.world.World;
|
|||
*
|
||||
*/
|
||||
public interface IUseAction {
|
||||
|
||||
|
||||
/**
|
||||
* Triggered when the player right clicks a block
|
||||
*
|
||||
*
|
||||
* @param stack The current itemstack
|
||||
* @param player The player
|
||||
* @param world The player's world
|
||||
|
@ -24,20 +26,20 @@ public interface IUseAction {
|
|||
* @param hitX X offset inside the block
|
||||
* @param hitY Y offset inside the block
|
||||
* @param hitZ Z offset inside the block
|
||||
*
|
||||
*
|
||||
* @return ActionResult for the type of action to perform
|
||||
*/
|
||||
public SpellCastResult onUse(ItemStack stack, EntityPlayer player, World world, BlockPos pos, EnumFacing side, float hitX, float hitY, float hitZ);
|
||||
|
||||
|
||||
/**
|
||||
* Triggered when the player right clicks
|
||||
*
|
||||
* @param stack The current itemstack
|
||||
*
|
||||
* @param stack The current itemstack
|
||||
* @param player The player
|
||||
* @param world The player's world
|
||||
* @param hitEntity The entity in focus, if any
|
||||
*
|
||||
*
|
||||
* @return ActionResult for the type of action to perform
|
||||
*/
|
||||
public SpellCastResult onUse(ItemStack stack, EntityPlayer player, World world, Entity hitEntity);
|
||||
public SpellCastResult onUse(ItemStack stack, EntityPlayer player, World world, @Nonnull Entity hitEntity);
|
||||
}
|
||||
|
|
262
src/main/java/com/minelittlepony/unicopia/spell/SpellFire.java
Normal file
262
src/main/java/com/minelittlepony/unicopia/spell/SpellFire.java
Normal file
|
@ -0,0 +1,262 @@
|
|||
package com.minelittlepony.unicopia.spell;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.minelittlepony.unicopia.Predicates;
|
||||
import com.minelittlepony.unicopia.entity.IMagicals;
|
||||
import com.minelittlepony.util.MagicalDamageSource;
|
||||
import com.minelittlepony.util.PosHelper;
|
||||
import com.minelittlepony.util.blockstate.IStateMapping;
|
||||
import com.minelittlepony.util.blockstate.StateMapList;
|
||||
import com.minelittlepony.util.shape.IShape;
|
||||
import com.minelittlepony.util.shape.Sphere;
|
||||
import com.minelittlepony.util.vector.VecHelper;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockBush;
|
||||
import net.minecraft.block.BlockDirt;
|
||||
import net.minecraft.block.BlockFarmland;
|
||||
import net.minecraft.block.BlockLeaves;
|
||||
import net.minecraft.block.BlockRedstoneWire;
|
||||
import net.minecraft.block.BlockSilverfish;
|
||||
import net.minecraft.block.BlockStoneBrick;
|
||||
import net.minecraft.block.BlockWall;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.dispenser.IBlockSource;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.item.EntityItem;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.EnumParticleTypes;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class SpellFire extends AbstractSpell implements IUseAction, IDispenceable {
|
||||
|
||||
public final StateMapList affected = new StateMapList();
|
||||
|
||||
private static final IShape visual_effect_region = new Sphere(false, 0.5);
|
||||
private static final IShape effect_range = new Sphere(false, 4);
|
||||
|
||||
public SpellFire() {
|
||||
affected.removeBlock(s -> s.getBlock() == Blocks.SNOW_LAYER || s.getBlock() == Blocks.SNOW);
|
||||
affected.removeBlock(s -> s.getBlock() instanceof BlockBush);
|
||||
|
||||
affected.replaceBlock(Blocks.CLAY, Blocks.HARDENED_CLAY);
|
||||
affected.replaceBlock(Blocks.OBSIDIAN, Blocks.LAVA);
|
||||
affected.replaceBlock(Blocks.GRASS, Blocks.DIRT);
|
||||
affected.replaceBlock(Blocks.MOSSY_COBBLESTONE, Blocks.COBBLESTONE);
|
||||
|
||||
affected.replaceProperty(Blocks.COBBLESTONE_WALL, BlockWall.VARIANT, BlockWall.EnumType.MOSSY, BlockWall.EnumType.NORMAL);
|
||||
affected.replaceProperty(Blocks.STONEBRICK, BlockStoneBrick.VARIANT, BlockStoneBrick.EnumType.MOSSY, BlockStoneBrick.EnumType.DEFAULT);
|
||||
affected.replaceProperty(Blocks.MONSTER_EGG, BlockSilverfish.VARIANT, BlockSilverfish.EnumType.MOSSY_STONEBRICK, BlockSilverfish.EnumType.STONEBRICK);
|
||||
affected.replaceProperty(Blocks.DIRT, BlockDirt.VARIANT, BlockDirt.DirtType.PODZOL, BlockDirt.DirtType.COARSE_DIRT);
|
||||
|
||||
affected.setProperty(Blocks.FARMLAND, BlockFarmland.MOISTURE, 0);
|
||||
|
||||
affected.add(IStateMapping.build(
|
||||
s -> s.getBlock() == Blocks.DIRT && s.getValue(BlockDirt.VARIANT) == BlockDirt.DirtType.DIRT,
|
||||
s -> Math.random() <= 0.15 ?
|
||||
s.withProperty(BlockDirt.VARIANT, BlockDirt.DirtType.COARSE_DIRT)
|
||||
: s));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentLevel() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setCurrentLevel(int level) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "fire";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(ICaster<?> source, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(ICaster<?> source, int level) {
|
||||
|
||||
source.spawnParticles(visual_effect_region, level * 6, pos -> {
|
||||
source.getWorld().spawnParticle(EnumParticleTypes.SMOKE_LARGE, pos.x, pos.y, pos.z, 0, 0, 0);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellCastResult onUse(ItemStack stack, EntityPlayer player, World world, BlockPos pos, EnumFacing side, float hitX, float hitY, float hitZ) {
|
||||
boolean result = false;
|
||||
|
||||
if (player == null || player.isSneaking()) {
|
||||
result = applyBlocks(player, world, pos);
|
||||
} else {
|
||||
|
||||
for (BlockPos i : PosHelper.getAllInRegionMutable(pos, effect_range)) {
|
||||
result |= applyBlocks(player, world, i);
|
||||
}
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
result = applyEntities(player, world, pos);
|
||||
}
|
||||
|
||||
return result ? SpellCastResult.DEFAULT : SpellCastResult.NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellCastResult onUse(ItemStack stack, EntityPlayer player, World world, @Nonnull Entity hitEntity) {
|
||||
return applyEntitySingle(player, world, hitEntity) ? SpellCastResult.DEFAULT : SpellCastResult.NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellCastResult onDispenced(BlockPos pos, EnumFacing facing, IBlockSource source) {
|
||||
pos = pos.offset(facing, 4);
|
||||
|
||||
boolean result = false;
|
||||
|
||||
for (BlockPos i : PosHelper.getAllInRegionMutable(pos, effect_range)) {
|
||||
result |= applyBlocks(null, source.getWorld(), i);
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
result = applyEntities(null, source.getWorld(), pos);
|
||||
}
|
||||
|
||||
return result ? SpellCastResult.NONE : SpellCastResult.DEFAULT;
|
||||
}
|
||||
|
||||
protected boolean applyBlocks(EntityPlayer owner, World world, BlockPos pos) {
|
||||
IBlockState state = world.getBlockState(pos);
|
||||
Block id = state.getBlock();
|
||||
|
||||
if (id != Blocks.AIR) {
|
||||
if (id == Blocks.ICE || id == Blocks.PACKED_ICE) {
|
||||
world.setBlockState(pos, (world.provider.doesWaterVaporize() ? Blocks.AIR : Blocks.WATER).getDefaultState());
|
||||
playEffect(world, pos);
|
||||
|
||||
return true;
|
||||
} else if (id == Blocks.NETHERRACK) {
|
||||
if (world.getBlockState(pos.up()).getMaterial() == Material.AIR) {
|
||||
|
||||
if (world.rand.nextInt(300) == 0) {
|
||||
world.setBlockState(pos.up(), Blocks.FIRE.getDefaultState());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} else if (id == Blocks.REDSTONE_WIRE) {
|
||||
int power = world.rand.nextInt(5) == 3 ? 15 : 3;
|
||||
|
||||
sendPower(world, pos, power, 3, 0);
|
||||
|
||||
return true;
|
||||
} else if (id == Blocks.SAND && world.rand.nextInt(10) == 0) {
|
||||
if (isSurroundedBySand(world, pos)) {
|
||||
world.setBlockState(pos, Blocks.GLASS.getDefaultState());
|
||||
|
||||
playEffect(world, pos);
|
||||
return true;
|
||||
}
|
||||
} else if (id instanceof BlockLeaves) {
|
||||
if (world.getBlockState(pos.up()).getMaterial() == Material.AIR) {
|
||||
world.setBlockState(pos.up(), Blocks.FIRE.getDefaultState());
|
||||
|
||||
playEffect(world, pos);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
IBlockState newState = affected.getConverted(state);
|
||||
|
||||
if (!state.equals(newState)) {
|
||||
world.setBlockState(pos, newState, 3);
|
||||
|
||||
playEffect(world, pos);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean applyEntities(EntityPlayer owner, World world, BlockPos pos) {
|
||||
return VecHelper
|
||||
.findAllEntitiesInRange(owner, world, pos, 3)
|
||||
.filter(i -> applyEntitySingle(owner, world, i))
|
||||
.count() > 0;
|
||||
}
|
||||
|
||||
protected boolean applyEntitySingle(Entity owner, World world, Entity e) {
|
||||
if ((!e.equals(owner) ||
|
||||
(owner instanceof EntityPlayer && !Predicates.MAGI.test(owner))) && !(e instanceof EntityItem)
|
||||
&& !(e instanceof IMagicals)) {
|
||||
e.setFire(60);
|
||||
e.attackEntityFrom(getDamageCause(e, (EntityLivingBase)owner), 0.1f);
|
||||
playEffect(world, e.getPosition());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected DamageSource getDamageCause(Entity target, EntityLivingBase attacker) {
|
||||
return MagicalDamageSource.causeMobDamage("fire", attacker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transmists power to a piece of redstone
|
||||
*/
|
||||
private void sendPower(World w, BlockPos pos, int power, int max, int i) {
|
||||
IBlockState state = w.getBlockState(pos);
|
||||
Block id = state.getBlock();
|
||||
|
||||
if (i < max && id == Blocks.REDSTONE_WIRE) {
|
||||
i++;
|
||||
|
||||
w.setBlockState(pos, state.withProperty(BlockRedstoneWire.POWER, power));
|
||||
|
||||
sendPower(w, pos.up(), power, max, i);
|
||||
sendPower(w, pos.down(), power, max, i);
|
||||
sendPower(w, pos.north(), power, max, i);
|
||||
sendPower(w, pos.south(), power, max, i);
|
||||
sendPower(w, pos.east(), power, max, i);
|
||||
sendPower(w, pos.west(), power, max, i);
|
||||
}
|
||||
}
|
||||
|
||||
protected void playEffect(World world, BlockPos pos) {
|
||||
int x = pos.getX();
|
||||
int y = pos.getY();
|
||||
int z = pos.getZ();
|
||||
world.playSound((double)((float)x + 0.5F), (double)((float)y + 0.5F), (double)((float)z + 0.5F), SoundEvents.BLOCK_FURNACE_FIRE_CRACKLE, SoundCategory.AMBIENT, 0.5F, 2.6F + (world.rand.nextFloat() - world.rand.nextFloat()) * 0.8F, true);
|
||||
|
||||
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, (double)x + Math.random(), (double)y + Math.random(), (double)z + Math.random(), 0.0D, 0.0D, 0.0D);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isSurroundedBySand(World w, BlockPos pos) {
|
||||
return isSand(w, pos.up()) && isSand(w, pos.down()) &&
|
||||
isSand(w, pos.north()) && isSand(w, pos.south()) &&
|
||||
isSand(w, pos.east()) && isSand(w, pos.west());
|
||||
}
|
||||
|
||||
public static boolean isSand(World world, BlockPos pos) {
|
||||
Block id = world.getBlockState(pos).getBlock();
|
||||
return id == Blocks.SAND || id == Blocks.GLASS;
|
||||
}
|
||||
}
|
168
src/main/java/com/minelittlepony/unicopia/spell/SpellIce.java
Normal file
168
src/main/java/com/minelittlepony/unicopia/spell/SpellIce.java
Normal file
|
@ -0,0 +1,168 @@
|
|||
package com.minelittlepony.unicopia.spell;
|
||||
|
||||
import com.minelittlepony.unicopia.UMaterials;
|
||||
import com.minelittlepony.util.MagicalDamageSource;
|
||||
import com.minelittlepony.util.PosHelper;
|
||||
import com.minelittlepony.util.blockstate.IStateMapping;
|
||||
import com.minelittlepony.util.blockstate.StateMapList;
|
||||
import com.minelittlepony.util.shape.Sphere;
|
||||
import com.minelittlepony.util.vector.VecHelper;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockBush;
|
||||
import net.minecraft.block.BlockLeaves;
|
||||
import net.minecraft.block.BlockRedstoneWire;
|
||||
import net.minecraft.block.BlockSnow;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.dispenser.IBlockSource;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.item.EntityTNTPrimed;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.EnumParticleTypes;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class SpellIce extends AbstractSpell implements IUseAction, IDispenceable {
|
||||
|
||||
public static final StateMapList affected = new StateMapList();
|
||||
|
||||
static {
|
||||
affected.add(IStateMapping.build(
|
||||
s -> s.getMaterial() == Material.WATER,
|
||||
s -> Blocks.ICE.getDefaultState()));
|
||||
affected.add(IStateMapping.build(
|
||||
s -> s.getMaterial() == Material.LAVA,
|
||||
s -> Blocks.OBSIDIAN.getDefaultState()));
|
||||
affected.add(IStateMapping.build(
|
||||
s -> s.getBlock() == Blocks.SNOW_LAYER,
|
||||
s -> s.cycleProperty(BlockSnow.LAYERS)));
|
||||
affected.replaceBlock(Blocks.FIRE, Blocks.AIR);
|
||||
affected.setProperty(Blocks.REDSTONE_WIRE, BlockRedstoneWire.POWER, 0);
|
||||
}
|
||||
|
||||
protected int rad = 3;
|
||||
|
||||
@Override
|
||||
public int getCurrentLevel() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentLevel(int level) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "ice";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(ICaster<?> source, int level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(ICaster<?> source, int level) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellCastResult onDispenced(BlockPos pos, EnumFacing facing, IBlockSource source) {
|
||||
return applyBlocks(null, source.getWorld(), pos.offset(facing, rad)) ? SpellCastResult.NONE : SpellCastResult.DEFAULT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellCastResult onUse(ItemStack stack, EntityPlayer player, World world, BlockPos pos, EnumFacing side, float hitX, float hitY, float hitZ) {
|
||||
if (player != null && player.isSneaking()) {
|
||||
applyBlockSingle(world, pos);
|
||||
} else {
|
||||
applyBlocks(player, world, pos);
|
||||
}
|
||||
|
||||
return SpellCastResult.DEFAULT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellCastResult onUse(ItemStack stack, EntityPlayer player, World world, Entity hitEntity) {
|
||||
if (hitEntity != null) {
|
||||
applyEntitySingle(player, hitEntity);
|
||||
return SpellCastResult.DEFAULT;
|
||||
}
|
||||
|
||||
return SpellCastResult.NONE;
|
||||
}
|
||||
|
||||
private boolean applyBlocks(EntityPlayer owner, World world, BlockPos pos) {
|
||||
|
||||
for (BlockPos i : PosHelper.getAllInRegionMutable(pos, new Sphere(false, rad))) {
|
||||
applyBlockSingle(world, i);
|
||||
}
|
||||
|
||||
return applyEntities(owner, world, pos);
|
||||
}
|
||||
|
||||
protected boolean applyEntities(EntityPlayer owner, World world, BlockPos pos) {
|
||||
return VecHelper.findAllEntitiesInRange(owner, world, pos, 3).filter(i -> {
|
||||
applyEntitySingle(owner, i);
|
||||
return true;
|
||||
}).count() > 0;
|
||||
}
|
||||
|
||||
protected void applyEntitySingle(EntityPlayer owner, Entity e) {
|
||||
if (e instanceof EntityTNTPrimed) {
|
||||
e.setDead();
|
||||
e.getEntityWorld().setBlockState(e.getPosition(), Blocks.TNT.getDefaultState());
|
||||
} else {
|
||||
if (e.isBurning()) {
|
||||
e.extinguish();
|
||||
} else {
|
||||
DamageSource d = MagicalDamageSource.causePlayerDamage("cold", owner);
|
||||
e.attackEntityFrom(d, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void applyBlockSingle(World world, BlockPos pos) {
|
||||
IBlockState state = world.getBlockState(pos);
|
||||
Block id = state.getBlock();
|
||||
|
||||
IBlockState converted = affected.getConverted(state);
|
||||
|
||||
if (!state.equals(converted)) {
|
||||
world.setBlockState(pos, converted, 3);
|
||||
} else if (state.getMaterial() != UMaterials.cloud && state.isSideSolid(world, pos, EnumFacing.UP)
|
||||
|| (id == Blocks.SNOW)
|
||||
|| (id instanceof BlockLeaves)) {
|
||||
incrementIce(world, pos.up());
|
||||
} else if (id == Blocks.ICE && world.rand.nextInt(10) == 0) {
|
||||
if (isSurroundedByIce(world, pos)) {
|
||||
world.setBlockState(pos, Blocks.PACKED_ICE.getDefaultState());
|
||||
}
|
||||
}
|
||||
|
||||
world.spawnParticle(EnumParticleTypes.WATER_SPLASH, pos.getX() + world.rand.nextFloat(), pos.getY() + 1, pos.getZ() + world.rand.nextFloat(), 0, 0, 0);
|
||||
}
|
||||
|
||||
public static boolean isSurroundedByIce(World w, BlockPos pos) {
|
||||
return isIce(w, pos.up()) && isIce(w, pos.down()) &&
|
||||
isIce(w, pos.north()) && isIce(w, pos.south()) &&
|
||||
isIce(w, pos.east()) && isIce(w, pos.west());
|
||||
}
|
||||
|
||||
public static boolean isIce(World world, BlockPos pos) {
|
||||
return world.getBlockState(pos).getMaterial() == Material.ICE;
|
||||
}
|
||||
|
||||
private void incrementIce(World world, BlockPos pos) {
|
||||
IBlockState state = world.getBlockState(pos);
|
||||
Block id = state.getBlock();
|
||||
|
||||
if (id == Blocks.AIR || (id instanceof BlockBush)) {
|
||||
world.setBlockState(pos, Blocks.SNOW_LAYER.getDefaultState(), 3);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,8 +25,10 @@ public class SpellRegistry {
|
|||
private final Map<String, Entry> entries = new HashMap<>();
|
||||
|
||||
private SpellRegistry() {
|
||||
registerSpell("shield", 0xffff00, SpellShield::new);
|
||||
registerSpell("charge", 0x0000ff, SpellCharge::new);
|
||||
registerSpell("shield", 0x66CDAA, SpellShield::new);
|
||||
registerSpell("charge", 0x0000AA, SpellCharge::new);
|
||||
registerSpell("fire", 0xFF0000, SpellFire::new);
|
||||
registerSpell("ice", 0xADD8E6, SpellIce::new);
|
||||
}
|
||||
|
||||
public IMagicEffect getSpellFromName(String name) {
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package com.minelittlepony.unicopia.spell;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import com.minelittlepony.unicopia.Predicates;
|
||||
import com.minelittlepony.unicopia.Race;
|
||||
import com.minelittlepony.unicopia.Unicopia;
|
||||
|
@ -9,7 +7,6 @@ import com.minelittlepony.unicopia.client.particle.Particles;
|
|||
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
|
||||
import com.minelittlepony.unicopia.power.IPower;
|
||||
import com.minelittlepony.util.ProjectileUtil;
|
||||
import com.minelittlepony.util.shape.IShape;
|
||||
import com.minelittlepony.util.shape.Sphere;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
|
@ -17,7 +14,6 @@ import net.minecraft.entity.EntityLivingBase;
|
|||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
|
@ -51,20 +47,10 @@ public class SpellShield extends AbstractSpell {
|
|||
}
|
||||
|
||||
protected void spawnParticles(ICaster<?> source, int strength) {
|
||||
IShape sphere = new Sphere(true, strength);
|
||||
|
||||
Random rand = source.getWorld().rand;
|
||||
|
||||
int x = source.getOrigin().getX();
|
||||
int y = source.getOrigin().getY();
|
||||
int z = source.getOrigin().getZ();
|
||||
|
||||
for (int i = 0; i < strength * 6; i++) {
|
||||
Vec3d pos = sphere.computePoint(rand);
|
||||
Particles.instance().spawnParticle(Unicopia.MAGIC_PARTICLE, false,
|
||||
pos.x + x, pos.y + y, pos.z + z,
|
||||
0, 0, 0);
|
||||
}
|
||||
source.spawnParticles(new Sphere(true, strength), strength * 6, pos -> {
|
||||
Particles.instance().spawnParticle(Unicopia.MAGIC_PARTICLE, false, pos.x, pos.y, pos.z, 0, 0, 0);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -90,20 +76,10 @@ public class SpellShield extends AbstractSpell {
|
|||
|
||||
int x = pos.getX(), y = pos.getY(), z = pos.getZ();
|
||||
|
||||
BlockPos begin = pos.add(-radius, -radius, -radius);
|
||||
BlockPos end = pos.add(radius, radius, radius);
|
||||
|
||||
AxisAlignedBB bb = new AxisAlignedBB(begin, end);
|
||||
|
||||
boolean ownerIsValid = Predicates.MAGI.test(owner);
|
||||
|
||||
for (Entity i : source.getWorld().getEntitiesInAABBexcluding(source.getEntity(), bb, entity -> !(ownerIsValid && entity.equals(owner)))) {
|
||||
source.findAllEntitiesInRange(radius).filter(entity -> !(ownerIsValid && entity.equals(owner))).forEach(i -> {
|
||||
double dist = i.getDistance(x, y, z);
|
||||
double dist2 = i.getDistance(x, y - i.getEyeHeight(), z);
|
||||
|
||||
if (dist > radius && dist2 > radius) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ProjectileUtil.isProjectile(i)) {
|
||||
if (!ProjectileUtil.isProjectileThrownBy(i, owner)) {
|
||||
|
@ -126,7 +102,7 @@ public class SpellShield extends AbstractSpell {
|
|||
-(y - i.posY) / force + (dist < 1 ? dist : 0),
|
||||
-(z - i.posZ) / force);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
package com.minelittlepony.util;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.google.common.collect.AbstractIterator;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.minelittlepony.util.shape.IShape;
|
||||
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.math.BlockPos.MutableBlockPos;
|
||||
|
||||
public class PosHelper {
|
||||
|
@ -27,6 +31,31 @@ public class PosHelper {
|
|||
return false;
|
||||
}
|
||||
|
||||
public static Iterable<MutableBlockPos> getAllInRegionMutable(BlockPos origin, IShape shape) {
|
||||
|
||||
Iterator<MutableBlockPos> iter = BlockPos.getAllInBoxMutable(
|
||||
origin.add(new BlockPos(shape.getLowerBound())),
|
||||
origin.add(new BlockPos(shape.getUpperBound()))
|
||||
).iterator();
|
||||
|
||||
return () -> new AbstractIterator<MutableBlockPos>() {
|
||||
@Override
|
||||
protected MutableBlockPos computeNext() {
|
||||
while (iter.hasNext()) {
|
||||
MutableBlockPos pos = iter.next();
|
||||
|
||||
if (shape.isPointInside(new Vec3d(pos.subtract(origin)))) {
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
|
||||
endOfData();
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a stream of mutable block positions ranging from the beginning position to end.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
package com.minelittlepony.util.blockstate;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.properties.IProperty;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.init.Blocks;
|
||||
|
||||
public interface IStateMapping extends Predicate<IBlockState>, Function<IBlockState, IBlockState> {
|
||||
|
||||
static IStateMapping removeBlock(Predicate<IBlockState> mapper) {
|
||||
return build(
|
||||
mapper,
|
||||
s -> Blocks.AIR.getDefaultState());
|
||||
}
|
||||
|
||||
static IStateMapping replaceBlock(Block from, Block to) {
|
||||
return build(
|
||||
s -> s.getBlock() == from,
|
||||
s -> to.getDefaultState());
|
||||
}
|
||||
|
||||
static <T extends Comparable<T>> IStateMapping replaceProperty(Block block, IProperty<T> property, T from, T to) {
|
||||
return build(
|
||||
s -> s.getBlock() == block && s.getValue(property) == from,
|
||||
s -> s.withProperty(property, to));
|
||||
}
|
||||
|
||||
static <T extends Comparable<T>> IStateMapping setProperty(Block block, IProperty<T> property, T to) {
|
||||
return build(
|
||||
s -> s.getBlock() == block,
|
||||
s -> s.withProperty(property, to));
|
||||
}
|
||||
|
||||
static IStateMapping build(Predicate<IBlockState> predicate, Function<IBlockState, IBlockState> converter) {
|
||||
return new IStateMapping() {
|
||||
@Override
|
||||
public boolean test(IBlockState state) {
|
||||
return predicate.test(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockState apply(IBlockState state) {
|
||||
return converter.apply(state);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this state can be converted by this mapping
|
||||
*
|
||||
* @param state State to check
|
||||
*
|
||||
* @return True if the state can be converted
|
||||
*/
|
||||
@Override
|
||||
default boolean test(@Nonnull IBlockState state) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given state based on this mapping
|
||||
*
|
||||
* @param state State to convert
|
||||
*
|
||||
* @return The converted state
|
||||
*/
|
||||
@Nonnull
|
||||
@Override
|
||||
default IBlockState apply(@Nonnull IBlockState state) {
|
||||
return state;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package com.minelittlepony.util.blockstate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.properties.IProperty;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
|
||||
/**
|
||||
* A collection of block-state mappings.
|
||||
*
|
||||
*/
|
||||
public class StateMapList extends ArrayList<IStateMapping> {
|
||||
private static final long serialVersionUID = 2602772651960588745L;
|
||||
|
||||
public void removeBlock(Predicate<IBlockState> mapper) {
|
||||
add(IStateMapping.removeBlock(mapper));
|
||||
}
|
||||
|
||||
public void replaceBlock(Block from, Block to) {
|
||||
add(IStateMapping.replaceBlock(from, to));
|
||||
}
|
||||
|
||||
public <T extends Comparable<T>> void replaceProperty(Block block, IProperty<T> property, T from, T to) {
|
||||
add(IStateMapping.replaceProperty(block, property, from, to));
|
||||
}
|
||||
|
||||
public <T extends Comparable<T>> void setProperty(Block block, IProperty<T> property, T to) {
|
||||
add(IStateMapping.setProperty(block, property, to));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this collection contains a mapping capable of converting the given state.
|
||||
*
|
||||
* @param state State to check
|
||||
*
|
||||
* @return True if the state can be converted
|
||||
*/
|
||||
public boolean canConvert(@Nullable IBlockState state) {
|
||||
return state != null && stream().anyMatch(i -> i.test(state));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to convert the given state based on the known mappings in this collection.
|
||||
*
|
||||
* @param state State to convert
|
||||
*
|
||||
* @return The converted state if there is one, otherwise null
|
||||
*/
|
||||
@Nonnull
|
||||
public IBlockState getConverted(@Nonnull IBlockState state) {
|
||||
for (IStateMapping i : this) {
|
||||
if (i.test(state)) {
|
||||
return i.apply(state);
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
}
|
|
@ -5,54 +5,64 @@ import java.util.Random;
|
|||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*Interface for a 3d shape, used for spawning particles in a designated area (or anything else you need shapes for).
|
||||
*/
|
||||
public interface IShape {
|
||||
|
||||
|
||||
/**
|
||||
* Rotates this shape around it's center.
|
||||
*
|
||||
*
|
||||
* @param u Rotate yaw
|
||||
* @param v Rotate pitch
|
||||
*
|
||||
*
|
||||
* @return This Shape
|
||||
*/
|
||||
public IShape setRotation(float u, float v);
|
||||
|
||||
|
||||
/**
|
||||
* Get the volume of space filled by this shape, or the surface area if hollow.
|
||||
*
|
||||
*
|
||||
* @return double volume
|
||||
*/
|
||||
public double getVolumeOfSpawnableSpace();
|
||||
|
||||
|
||||
/**
|
||||
* X offset from the shape's origin.
|
||||
*
|
||||
*
|
||||
* @return X
|
||||
*/
|
||||
public double getXOffset();
|
||||
|
||||
|
||||
/**
|
||||
* Y offset from the shape's origin.
|
||||
*
|
||||
*
|
||||
* @return Y
|
||||
*/
|
||||
public double getYOffset();
|
||||
|
||||
|
||||
/**
|
||||
* Z offset from the shape's origin.
|
||||
*
|
||||
*
|
||||
* @return Z
|
||||
*/
|
||||
public double getZOffset();
|
||||
|
||||
|
||||
/**
|
||||
* Gets the lower bounds of the region occupied by this shape.
|
||||
*/
|
||||
public Vec3d getLowerBound();
|
||||
|
||||
/**
|
||||
* Gets the upper bound of the region occupied by this shape.
|
||||
*/
|
||||
public Vec3d getUpperBound();
|
||||
|
||||
/**
|
||||
* Computes a random coordinate that falls within this shape's designated area.
|
||||
*/
|
||||
public Vec3d computePoint(Random rand);
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the given point is on the edge, or if not hollow the inside, of this shape.
|
||||
* @return
|
||||
|
|
|
@ -78,7 +78,7 @@ public class Line implements IShape {
|
|||
|
||||
public Vec3d computePoint(Random rand) {
|
||||
double distance = MathHelper.nextDouble(rand, 0, len);
|
||||
return (new Vec3d(distance * dX, distance * dY, distance * dZ)).rotateYaw(yaw).rotatePitch(pitch);
|
||||
return new Vec3d(dX, dY, dZ).scale(distance).add(sX, sY, sZ).rotateYaw(yaw).rotatePitch(pitch);
|
||||
}
|
||||
|
||||
public Line setRotation(float u, float v) {
|
||||
|
@ -89,6 +89,17 @@ public class Line implements IShape {
|
|||
|
||||
public boolean isPointInside(Vec3d point) {
|
||||
point = point.rotateYaw(-yaw).rotatePitch(-pitch);
|
||||
|
||||
return point.x/dX == point.y/dY && point.x/dX == point.z/dZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3d getLowerBound() {
|
||||
return new Vec3d(sX, sY, sZ).rotateYaw(yaw).rotatePitch(pitch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3d getUpperBound() {
|
||||
return new Vec3d(sX + dX, sY + dY, sZ + dZ).scale(len).rotateYaw(yaw).rotatePitch(pitch);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,7 +117,19 @@ public class Sphere implements IShape {
|
|||
public boolean isPointInside(Vec3d point) {
|
||||
point = point.rotateYaw(-yaw).rotatePitch(-pitch);
|
||||
point = new Vec3d(point.x / stretch.x, point.y / stretch.y, point.z / stretch.z);
|
||||
|
||||
double dist = point.length();
|
||||
|
||||
return hollow ? dist == rad : dist <= rad;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3d getLowerBound() {
|
||||
return new Vec3d(-rad * stretch.x, -rad * stretch.y, -rad * stretch.z).rotateYaw(yaw).rotatePitch(pitch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3d getUpperBound() {
|
||||
return new Vec3d(rad * stretch.x, rad * stretch.y, rad * stretch.z).rotateYaw(yaw).rotatePitch(pitch);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.minelittlepony.util.vector;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
@ -11,8 +12,10 @@ import net.minecraft.entity.EntityLivingBase;
|
|||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.util.EntitySelectors;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class VecHelper {
|
||||
|
||||
|
@ -45,10 +48,25 @@ public class VecHelper {
|
|||
return null;
|
||||
}
|
||||
|
||||
public static Stream<Entity> findAllEntitiesInRange(@Nullable Entity origin, World w, BlockPos pos, double radius) {
|
||||
|
||||
BlockPos begin = pos.add(-radius, -radius, -radius);
|
||||
BlockPos end = pos.add(radius, radius, radius);
|
||||
|
||||
AxisAlignedBB bb = new AxisAlignedBB(begin, end);
|
||||
|
||||
return w.getEntitiesInAABBexcluding(origin, bb, null).stream().filter(e -> {
|
||||
double dist = e.getDistance(pos.getX(), pos.getY(), pos.getZ());
|
||||
double dist2 = e.getDistance(pos.getX(), pos.getY() - e.getEyeHeight(), pos.getZ());
|
||||
|
||||
return dist <= radius || dist2 <= radius;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all entities within a given range from the player.
|
||||
*/
|
||||
public static List<Entity> getWithinRange(EntityPlayer player, double reach, @Nullable Predicate <? super Entity > predicate) {
|
||||
public static List<Entity> getWithinRange(EntityPlayer player, double reach, @Nullable Predicate<? super Entity> predicate) {
|
||||
Vec3d look = player.getLook(0).scale(reach);
|
||||
|
||||
return player.world.getEntitiesInAABBexcluding(player, player
|
||||
|
|
Loading…
Reference in a new issue