Add imbuement altar

- Adds imbuement altar block and associated tile entity
- Adds basic functionality for imbuing wizard armour (other stuff to be decided)
- Incorporates imbuement altar into glowing overlay model event (this could do with being tidied up and generalised)
- Adds a TESR for the ray effect (based on some of the oldest code in the entire mod, which definitely needs improving!)
- Adds a simple sound effect for the imbuement process, needs upgrading to a ticked sound later
This commit is contained in:
Electroblob77
2020-06-17 23:44:02 +01:00
parent 99d0d115c7
commit 8e8e249426
25 changed files with 619 additions and 7 deletions
@@ -0,0 +1,204 @@
package electroblob.wizardry.tileentity;
import electroblob.wizardry.block.BlockReceptacle;
import electroblob.wizardry.constants.Element;
import electroblob.wizardry.item.IManaStoringItem;
import electroblob.wizardry.item.ItemWizardArmour;
import electroblob.wizardry.registry.WizardryItems;
import electroblob.wizardry.registry.WizardrySounds;
import electroblob.wizardry.util.GeometryUtils;
import electroblob.wizardry.util.ParticleBuilder;
import electroblob.wizardry.util.ParticleBuilder.Type;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ITickable;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.math.Vec3d;
import javax.annotation.Nullable;
import java.util.Arrays;
public class TileEntityImbuementAltar extends TileEntity implements ITickable {
private static final int IMBUEMENT_DURATION = 140;
private ItemStack stack;
private int imbuementTimer;
private Element displayElement;
public TileEntityImbuementAltar(){
stack = ItemStack.EMPTY;
}
public void setStack(ItemStack stack){
this.stack = stack;
checkRecipe();
}
public void checkRecipe(){
if(getResult().isEmpty()){
imbuementTimer = 0;
}else if(imbuementTimer == 0){
imbuementTimer = 1;
}else{
return; // Don't sync if nothing changed
}
world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3); // Sync
}
public ItemStack getStack(){
return stack;
}
@Override
public void update(){
if(imbuementTimer > 0){
if(imbuementTimer == 1){ // Has to be done here because of syncing
world.playSound(pos.getX() + 0.5, pos.getY() + 1, pos.getZ() + 0.5,
WizardrySounds.BLOCK_IMBUEMENT_ALTAR_IMBUE, SoundCategory.BLOCKS, 1, 1, false);
}
ItemStack result = getResult();
if(result.isEmpty()){
imbuementTimer = 0;
}else{
if(imbuementTimer++ >= IMBUEMENT_DURATION){
this.stack = result;
consumeReceptacleContents();
imbuementTimer = 0;
displayElement = null;
}
if(world.isRemote && world.rand.nextInt(2) == 0){
Element[] elements = getReceptacleElements();
Vec3d centre = GeometryUtils.getCentre(this.pos.up());
for(int i = 0; i < elements.length; i++){
if(elements[i] == null) continue;
Vec3d offset = new Vec3d(EnumFacing.byHorizontalIndex(i).getDirectionVec());
Vec3d vec = GeometryUtils.getCentre(this.pos).add(0, 0.3, 0).add(offset.scale(0.7));
int[] colours = BlockReceptacle.PARTICLE_COLOURS.get(elements[i]);
ParticleBuilder.create(Type.DUST, world.rand, vec.x, vec.y, vec.z, 0.1, false)
.vel(centre.subtract(vec).scale(0.02)).clr(colours[1]).fade(colours[2]).time(50).spawn(world);
}
}
}
}
}
/** Returns the element to use for the visual ray effect colours, or null if they should not be displayed. */
public Element getDisplayElement(){
return displayElement;
}
/** Returns how complete the current action is (from 0 to 1), or 0 if no action is being performed. */
public float getImbuementProgress(){
return (float)imbuementTimer / IMBUEMENT_DURATION;
}
private ItemStack getResult(){
if(stack.getItem() instanceof ItemWizardArmour && ((ItemWizardArmour)stack.getItem()).element == null){
Element[] elements = getReceptacleElements();
if(Arrays.stream(elements).distinct().count() == 1 && elements[0] != null){ // All the same element
ItemStack result = new ItemStack(WizardryItems.getArmour(elements[0], ((ItemWizardArmour)stack.getItem()).armorType));
displayElement = elements[0];
result.setTagCompound(stack.getTagCompound());
((IManaStoringItem)result.getItem()).setMana(result, ((ItemWizardArmour)stack.getItem()).getMana(stack));
return result;
}
}
displayElement = null;
return ItemStack.EMPTY;
}
/** Returns the elements of the 4 adjacent receptacles, in SWNE order. Null means an empty or missing receptacle. */
private Element[] getReceptacleElements(){
Element[] elements = new Element[4];
for(EnumFacing side : EnumFacing.HORIZONTALS){
TileEntity tileEntity = world.getTileEntity(pos.offset(side));
if(tileEntity instanceof TileEntityReceptacle){
elements[side.getHorizontalIndex()] = ((TileEntityReceptacle)tileEntity).getElement();
}else{
elements[side.getHorizontalIndex()] = null;
}
}
return elements;
}
/** Empties the 4 adjacent receptacles. */
private void consumeReceptacleContents(){
for(EnumFacing side : EnumFacing.HORIZONTALS){
TileEntity tileEntity = world.getTileEntity(pos.offset(side));
if(tileEntity instanceof TileEntityReceptacle){
((TileEntityReceptacle)tileEntity).setElement(null);
}
}
}
@Override
public NBTTagCompound writeToNBT(NBTTagCompound nbt){
super.writeToNBT(nbt);
NBTTagCompound itemTag = new NBTTagCompound();
stack.writeToNBT(itemTag);
nbt.setTag("item", itemTag);
nbt.setInteger("imbuementTimer", imbuementTimer);
return nbt;
}
@Override
public void readFromNBT(NBTTagCompound nbt){
super.readFromNBT(nbt);
NBTTagCompound itemTag = nbt.getCompoundTag("item");
this.stack = new ItemStack(itemTag);
this.imbuementTimer = nbt.getInteger("imbuementTimer");
}
@Override
public NBTTagCompound getUpdateTag(){
return this.writeToNBT(new NBTTagCompound());
}
@Nullable
@Override
public SPacketUpdateTileEntity getUpdatePacket(){
return new SPacketUpdateTileEntity(pos, 0, this.getUpdateTag());
}
@Override
public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt){
readFromNBT(pkt.getNbtCompound());
}
}